ToastNotificationsを用いた通知表示

2021-03-14

ToastNotifications

なお、ToastNotificationsには、MessageOptions内にNotificationClickActionというクリック通知用アクションが用意されているが、
うまく動作しなかったため、代替処理を行っている。

WpfApp23

ViewMainView.xaml

<Window x:Class="WpfApp23.View.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:local="clr-namespace:WpfApp23.View"
        xmlns:vm="clr-namespace:WpfApp23.ViewModel"
        mc:Ignorable="d"
        Title="MainView" Height="200" Width="400">

    <Window.DataContext>
        <vm:MainViewModel/>
    </Window.DataContext>

    <i:Interaction.Triggers>
        <i:EventTrigger EventName ="ContentRendered">
            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="OnContentRendered" />
        </i:EventTrigger>
        <i:EventTrigger EventName ="Closing">
            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="OnClosing" />
        </i:EventTrigger>
    </i:Interaction.Triggers>

    <Grid>
        <Button Content="ShowToast" Margin="110,45,177,39">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="OnButtonClicked" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</Window>

ViewMainView.xaml.cs

using System.Windows;

namespace WpfApp23.View
{
    /// <summary>
    /// MainView.xaml の相互作用ロジック
    /// </summary>
    public partial class MainView : Window
    {
        public MainView()
        {
            InitializeComponent();
        }
    }
}

ViewModelMainViewModel.cs

using MaterialNotification.Model;
using System;

namespace WpfApp23.ViewModel
{
    public class MainViewModel : Livet.ViewModel
    {
        private NotificationModel notificationModel = null;

        public void OnContentRendered()
        {
            notificationModel = new NotificationModel();
        }

        public void OnClosing()
        {
            if (notificationModel != null)
                notificationModel.Dispose();
        }

        public void OnButtonClicked()
        {
            notificationModel.ShowNotification("タイトル", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")).Clicked += (object sender, EventArgs e) =>
            {
            };
        }
    }
}

MaterialNotification

ModelNotificationClickModel.cs

using System;

namespace MaterialNotification.Model
{
    public class NotificationClickModel
    {
        public event EventHandler Clicked;

        public void RaiseClickEvent()
        {
            if (Clicked != null)
                Clicked(this, EventArgs.Empty);
        }
    }
}

ModelNotificationModel.cs

using System;
using ToastNotifications;
using ToastNotifications.Lifetime;
using ToastNotifications.Position;
using MaterialNotification.ViewModel;
using System.Windows.Threading;

namespace MaterialNotification.Model
{
    public class NotificationModel : IDisposable
    {
        private Notifier notifier = null;

        public NotificationModel()
        {
            notifier = new Notifier(config =>
            {
                config.LifetimeSupervisor = new TimeAndCountBasedLifetimeSupervisor(TimeSpan.FromSeconds(5), MaximumNotificationCount.FromCount(5));
                config.PositionProvider = new PrimaryScreenPositionProvider(Corner.BottomRight, 10, 10);
                config.Dispatcher = Dispatcher.CurrentDispatcher;
            });
        }

        public void Dispose()
        {
            if (notifier != null)
                notifier.Dispose();
        }

        public NotificationClickModel ShowNotification(string title, string message)
        {
            NotificationClickModel notificationClickModel = new NotificationClickModel();
            notifier.ShowNotification(title, message).Clicked += (object sender, EventArgs e) =>
            {
                notificationClickModel.RaiseClickEvent();
            };

            return notificationClickModel;
        }
    }
}

ViewNotificationView.xaml

<core:NotificationDisplayPart
        x:Class="MaterialNotification.View.NotificationView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MaterialNotification.View"
        xmlns:core="clr-namespace:ToastNotifications.Core;assembly=ToastNotifications"
        mc:Ignorable="d"
        d:DesignHeight="120" d:DesignWidth="250" Background="Black" Opacity="0.85" Cursor="Hand">

    <Grid Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Title}" Foreground="White" FontSize="17"/>
        <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding Message}" Foreground="White" TextWrapping="Wrap"/>
    </Grid>
</core:NotificationDisplayPart>

ViewNotificationView.xaml.cs

using ToastNotifications.Core;

namespace MaterialNotification.View
{
    /// <summary>
    /// NotificationView.xaml の相互作用ロジック
    /// </summary>
    public partial class NotificationView : NotificationDisplayPart
    {
        public NotificationView(ViewModel.NotificationViewModel notificationViewModel)
        {
            InitializeComponent();
            Bind(notificationViewModel);
        }
    }
}

ViewModelNotificationViewModel.cs

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using ToastNotifications.Core;

namespace MaterialNotification.ViewModel
{
    public class NotificationViewModel : NotificationBase, INotifyPropertyChanged
    {
        public event EventHandler Clicked;

        private View.NotificationView notificationView = null;

        public override NotificationDisplayPart DisplayPart => notificationView;

        public NotificationViewModel(string title, string message, MessageOptions messageOptions) : base(message, messageOptions)
        {
            Title = title;
            Message = message;

            notificationView = new View.NotificationView(this);
            notificationView.MouseDown += (object sender, System.Windows.Input.MouseButtonEventArgs e) =>
            {
                if (Clicked != null)
                    Clicked(this, EventArgs.Empty);
            };
        }

        private string _title;
        public string Title
        {
            get
            {
                return _title;
            }
            set
            {
                _title = value;
                OnPropertyChanged();
            }
        }

        private string _message;
        public string Message
        {
            get
            {
                return _message;
            }
            set
            {
                _message = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

ViewModelNotificationViewModelExtensions.cs

using ToastNotifications;
using ToastNotifications.Core;

namespace MaterialNotification.ViewModel
{
    public static class NotificationViewModelExtensions
    {
        public static NotificationViewModel ShowNotification(this Notifier notifier, string title, string message, MessageOptions messageOptions = null)
        {
            NotificationViewModel notificationViewModel = new NotificationViewModel(title, message, messageOptions);
            notifier.Notify(() => notificationViewModel);

            return notificationViewModel;
        }
    }
}