65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 吐司通知

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.97/5 (14投票s)

2016 年 1 月 24 日

MIT

5分钟阅读

viewsIcon

81391

downloadIcon

4314

WPF 应用程序的精美吐司通知, 易于使用并支持 MVVM 模式。

 

只需下载项目演示,使用 Nuget 恢复丢失的包即可。 Smile | :)

引言

适用于 WPF 应用程序的精美弹出通知,易于使用并支持 MVVM 模式。一个在屏幕底部显示带有图片、标题和内容的简短通知窗口。您可以使用默认实现或构建自己的自定义通知。

Github

您可以在 Github 上查看该项目 此处,下载源代码和应用演示,尽情享用。 Smile | :)

演示展示了如何使用弹出通知,以默认实现或您自己的自定义实现方式显示它。

Nuget

WPF 弹出通知可在 NuGet 上找到,您可以使用 NuGet 管理器安装它,或在程序包管理器控制台中运行以下命令。

PM> Install-Package WPFNotification

 

注意:  在 WPF 弹出通知 - 深入探讨  文章中,我逐步解释了该程序包背后的代码。

在本文中,我们将演示

 

特点

  • 简单、轻量级、精美的弹出通知,带有标题、内容和可覆盖的预定义图片,显示在屏幕底部。
  • 支持 MVVM 模式。
  • 支持 Windows 7 或更高版本。
  • 支持在不同屏幕分辨率下显示通知。
  • 可配置,您可以使用默认通知配置,或使用以下属性进行重新配置
    • 显示时长
    • 宽度
    • 高度
    • 通知模板
    • 通知流方向,这决定了新通知窗口将如何出现。可用选项为
      • 右下(默认)。
      • 左下。
      • 左上。
      • 右上。
  • 可定制
    • 您可以实现自己的通知
  • 一次显示一个通知,如果有其他通知,它们将排队等待,并在空间可用时显示。
  • 当鼠标悬停在通知上时,阻止通知淡出。
  • 允许清除通知列表和通知缓冲区列表中的所有通知

 

入门

添加通知程序集

  • 打开 Visual Studio,打开一个现有的 WPF 应用程序或创建一个新的 WPF 应用程序项目。
  • 获取最新的 WPFToastNotification 发布版本 并将其内容解压缩到磁盘,或使用 NuGet 安装 WPFNotification 程序包。
  • 添加对 WPFNotification.dll 的程序集引用。
  • 修改 App.xaml 并添加以下资源字典引用
<ResourceDictionary>
  <ResourceDictionary.MergedDictionaries>
   <ResourceDictionary Source="/WPFNotification;component/Assets/NotificationUI.xaml"/>
  </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
注意

如果您使用 NuGet 安装 WPFNotification 程序包。它会自动添加程序集引用并为您修改 App.xaml 文件。

 

显示默认弹出通知

假设通知将在用户单击按钮时显示

  1. 如果您使用 MVVM 模式,您需要执行以下步骤
    • INotificationDialogService 注册到您的 IOC 容器中。我正在使用 SimpleIOC 容器。
    SimpleIoc.Default.Register<INotificationDialogService, NotificationDialogService>();
    • INotificationDialogService 注入到您的 viewModel 中。
    • 创建 Notification 对象,包含您的 TitleMessage 和可选的 ImgURL(如果为 null,则会显示默认的预定义图片)。
    • 最后,调用 ShowNotificationWindow 方法并传入通知对象。
    public class MainViewModel : ViewModelBase
    {
            private readonly INotificationDialogService _dailogService;
    
            // inject INotificationDialogservice
    
            public MainViewModel(INotificationDialogService dailogService)
            {
                _dailogService = dailogService;
            }
    
            private RelayCommand _defaultNotification;
    
            /// <summary>
            /// The DefaultNotification command.
            /// Create Notification object and send it to NotificationDialogService 
            /// to display the notification.
            /// </summary>
    
            public RelayCommand DefaultNotification
            {
                get
                {
                    return _defaultNotification
                        ?? (_defaultNotification = new RelayCommand(
                        () =>
                        {
                          // Create the notification object
                            var newNotification = new Notification()
                            {
                                Title = "Machine error",
                                Message = "Error!! Please check your Machine Code and Try Again"
                            };
                          // call the ShowNotificationWindow Method with the notification object
                            _dailogService.ShowNotificationWindow(newNotification);
                        }));
                }
            }
    }
  2. 如果您使用代码隐藏,您需要执行以下步骤
    • 创建 INotificationDialogService 对象。
    • 创建 Notification 对象,包含您的 TitleMessage 和可选的 ImgURL(如果为 null,则会显示默认的预定义图片)。
    • 最后,调用 ShowNotificationWindow 方法并传入通知对象。
    private void Button_Click(object sender, RoutedEventArgs e)
            {
                INotificationDialogService _dailogService = new NotificationDialogService();
                var newNotification = new Notification()
                {
                    Title = "Machine error",
                    Message = "Error!! Please check your Machine Code and Try Again"
                };
                _dailogService.ShowNotificationWindow(newNotification);
            }

现在您应该会在屏幕上看到通知,如下面的图所示

 

创建自定义通知

假设我们将创建一个邮件通知,该通知将在用户单击按钮时显示。

要创建自定义通知,我们需要执行五个步骤

步骤 1

创建自定义通知模型,例如 MailNotification 类,如下所示

 public class MailNotification
    {
        public string Title { get; set; }
        public string Sender { get; set; }
        public string Content { get; set; }
    }
注意

如果您想使用默认通知模型,但需要更改通知 UI,请忽略此步骤,直接从第 2 步开始。

第二步

创建自定义通知 UI,例如 NotificationItem.xaml(用户控件),并将其绑定到 MailNotification 模型,如下所示

<UserControl x:Class="WPFNotificationDemo.Assets.NotificationItem"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             xmlns:self="ASTA.Host.Presentation.Views.Notifications"
             d:DesignHeight="180" d:DesignWidth="320"
             x:Name="NotificationWindow"
             Background="Transparent">
    <UserControl.Triggers>
        <EventTrigger RoutedEvent="Button.Click" SourceName="CloseButton">
            <BeginStoryboard>
                <Storyboard >
                    <DoubleAnimation Storyboard.TargetName="NotificationWindow" 
                    From="1" To="0" 
                    Storyboard.TargetProperty="(Grid.Opacity)" Duration="0:0:0"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </UserControl.Triggers>
    <UserControl.Style>
        <Style TargetType="UserControl">
            <Style.Triggers>
                <DataTrigger Binding="
                {Binding ElementName=NotificationWindow,Path=Opacity}" Value="0"/>
            </Style.Triggers>
        </Style>
    </UserControl.Style>
    <Grid Background="Transparent">
        <Border Name="border"
                CornerRadius="10"
                Margin="10"
                BorderThickness="1"
                
                BorderBrush="{DynamicResource Accent}">
            <Border.Background>
                <SolidColorBrush Color="{DynamicResource WindowBackgroundColor}" />
            </Border.Background>
            <Border.Resources>
                <Storyboard x:Key="BackgroundAnimation">
                    <ColorAnimation Storyboard.TargetName="WindowBorderBackground" 
                    Storyboard.TargetProperty="Color" 
                    To="{DynamicResource WindowBackgroundColor}" Duration="0:0:.6" />
                </Storyboard>
            </Border.Resources>
            <Border.Effect>
                <DropShadowEffect ShadowDepth="0" Opacity="0.8" BlurRadius="10"/>
            </Border.Effect>
            <Grid Height="160" Width="300" Margin="0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"></RowDefinition>
                    <RowDefinition Height="*"></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                    <ColumnDefinition Width="*"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Image Grid.RowSpan="2" Source="/Resources/Images/newMail.png" 
                Margin="4" Width="80"></Image>
                <TextBlock Text="{Binding Path=Title}" 
                TextOptions.TextRenderingMode="ClearType" 
                TextOptions.TextFormattingMode="Display" 
                Foreground="DimGray" TextAlignment="Center"
                                   FontFamily="Arial" 
                                   FontSize="14" FontWeight="Bold" 
                                   VerticalAlignment="Center"  Margin="4,4,4,2" 
                                   TextWrapping="Wrap" TextTrimming="CharacterEllipsis" 
                                   Grid.ColumnSpan="2" />
                <Button x:Name="CloseButton"
                        Grid.Column="1"
                        HorizontalAlignment="Right"
                        Margin="0,0,27,0"
                        Click="CloseButton_Click"
                        Style="{StaticResource SystemCloseButton}"
                        Width="16"
                        Height="16" >
                    <Button.Content>
                        <Grid Width="10" Height="12" 
                        RenderTransform="1,0,0,1,0,1">
                            <Path Data="M0,0 L8,7 M8,0 L0,7 Z" 
                            Width="8" Height="7" VerticalAlignment="Center" 
                            HorizontalAlignment="Center"
                            Stroke="{Binding Foreground, 
				RelativeSource={RelativeSource Mode=FindAncestor, 
                            AncestorType=Button}}" StrokeThickness="1.5"  />
                        </Grid>
                    </Button.Content>
                </Button>
                <StackPanel Orientation="Vertical" Grid.Row="1" 
                Grid.Column="1" VerticalAlignment="Stretch">
                    <StackPanel Orientation="Horizontal" Margin="5">
                        <TextBlock Text="From :" HorizontalAlignment="Left" 
                        VerticalAlignment="Top" FontWeight="Black" 
                        Foreground="DarkGoldenrod"></TextBlock>
                        <TextBlock Grid.Row="0"
                               Grid.Column="1"
                               Text="{Binding Sender}"
                               TextTrimming="CharacterEllipsis"
                               TextWrapping="Wrap"
                               FontFamily="Arial"
                               VerticalAlignment="Center"
                               Foreground="Black"
                               Margin="5,0,0,0"
                               Width="145"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal"  Margin="5">
                        
                        <TextBlock Grid.Row="1"
                               Grid.Column="0" Grid.ColumnSpan="2"
                               Text="{Binding Content}"
                               TextTrimming="CharacterEllipsis"
                               TextWrapping="Wrap"
                               FontFamily="Arial"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Stretch"
                               Foreground="Black"
                               Margin="5,0,0,0"
                               Width="150"/>
                    </StackPanel>
                </StackPanel>
            </Grid>
        </Border>
    </Grid>
</UserControl>

我们需要在 NotificationItem.xaml.cs 中的关闭按钮上添加一个 click 事件,以便在显示时长结束之前立即关闭通知窗口。

private void CloseButton_Click(object sender, RoutedEventArgs e)
        {
            Window parentWindow = Window.GetWindow(this);
            this.Visibility = Visibility.Hidden;
            parentWindow.Close();
        }

步骤 3

创建资源字典文件,例如 MailNotificationUI.xaml,添加 dataTemplate 来定义通知数据的表示形式,并且您必须为其命名,例如 x:Key="MailNotificationTemplate",因为我们在创建 NotificationConfiguration 对象时需要这个名称。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:Model="clr-namespace:WPFNotificationDemo.Model"
                    xmlns:NotificationView="clr-namespace:WPFNotificationDemo.Assets">

    <DataTemplate x:Key="MailNotificationTemplate" 
    DataType="{x:Type Model:MailNotification}">
        <NotificationView:NotificationItem/>
    </DataTemplate>

</ResourceDictionary>

步骤 4

修改 App.xaml 并添加 MailNotificationUI.xaml 资源字典引用

<Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source=
                "/WPFNotification;component/Assets/NotificationUI.xaml" />
                <ResourceDictionary Source=
                "/Assets/MailNotificationUI.xaml" />
            </ResourceDictionary.MergedDictionaries>
      <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
    </ResourceDictionary>
  </Application.Resources>

步骤 5

显示邮件通知

  1. 如果您使用 MVVM 模式,您需要执行以下步骤
    • INotificationDialogService 注册到您的 IOC 容器中。
    SimpleIoc.Default.Register<INotificationDialogService, NotificationDialogService>();
    • INotificationDialogService 注入到您的 viewModel 中。
    • 创建 NotificationConfiguration 对象,并将 TemplateName 设置为您的 dataTemplate 的名称,请记住我们在第 3 步中提到的内容。
    • 最后调用 ShowNotificationWindow 方法,并传入 notification 对象和 configuration 对象。
    public class MainViewModel : ViewModelBase
    {
            private readonly INotificationDialogService _dailogService;
    
            // inject INotificationDialogservice
    
            public MainViewModel(INotificationDialogService dailogService)
            {
                _dailogService = dailogService;
            }
    
            private RelayCommand _mailNotification;
    
            /// <summary>
            /// The MailNotification command.
            /// Create Notification and NotificationConfiguration objects,
            /// and send them to NotificationDialogService to display the notification.
            /// </summary>
            public RelayCommand MailNotification
            {
                get
                {
                    return _mailNotification
                        ?? (_mailNotification = new RelayCommand(
                        () =>
                        {
                          // create notification object
                            var newNotification = new MailNotification()
                            {
                                Title = "Vacation Request",
                                Sender = "Mohamed Magdy",
                                Content = "I would like to request for vacation 
                                           from 20/12/2015 to 30/12/2015 ............."
                            };
                           // create configuration object
                            var configuration = new NotificationConfiguration(TimeSpan.Zero, null,
                                                null,Constants.MailNotificationTemplateName);
                            // call show method with notification and configuration objects
                            _dailogService.ShowNotificationWindow(newNotification, configuration);
                        }));
                }
            }
    }
    注意

    要更改通知流方向,您必须在 Configuration 对象中设置 NotificationFlowDirection 属性(默认值为 RightBottom),然后将其传递给 ShowNotificationWindow 方法。

    当配置对象的任何属性设置为 null 时,它将使用默认值,除了 displayDuration 属性必须设置为 TimeSpan.Zero 才能使用默认值(2 秒)。

    var configuration = new NotificationConfiguration(TimeSpan.Zero, null, 
                                                      null, Constants.MailNotificationTemplateName, 
                                                      NotificationFlowDirection.LeftUp);
     _dailogService.ShowNotificationWindow(newNotification, configuration);
  2. 如果您使用代码隐藏,您需要执行以下步骤
    • 创建 INotificationDialogService 对象。
    • 创建 MailNotification 对象。
    • 创建 NotificationConfiguration 对象,并将 TemplateName 设置为您的 dataTemplate 的名称,请记住我们在第 3 步中提到的内容。
    • 最后,调用 ShowNotificationWindow 方法,并传入 notification 对象和 configuration 对象。
    private void Button_Click(object sender, RoutedEventArgs e)
            {
                INotificationDialogService _dailogService = new NotificationDialogService();
    
               var newNotification = new MailNotification()
                   {
                      Title = "Vacation Request",
                      Sender = "Mohamed Magdy",
                      Content = "I would like to request for vacation from 20/12/2015 
                                to 30/12/2015 ............."
                   };
           var configuration = new NotificationConfiguration(TimeSpan.Zero, null,
                                    null, Constants.MailNotificationTemplateName);
           _dailogService.ShowNotificationWindow(newNotification, configuration);
    
            }

现在,您应该会在屏幕上看到邮件通知,如下面的图所示

清除通知

在某些情况下,我们需要清除所有通知,例如,在关闭 应用程序后,我们不需要通知继续显示 屏幕上。所以,要清除缓冲区列表中的所有通知,您必须在 NotificationDialogService 类中调用 ClearNotifications 方法。

public class ViewModelLocator {
.
.
.
        public static void Cleanup()
        {
            var notificationService = ServiceLocator.Current.GetInstance<INotificationDialogService>();
            notificationService.ClearNotifications();
            App.Current.Shutdown();
        }
} 

历史

  • 2016 年 1 月 24 日  原始帖子
  • 2016 年 2 月 12 日 添加指向 WPFToastNotification - 深入探讨 文章的链接。
  • 2016 年 6 月 28 日 添加新功能
    • 支持 Windows 7 或更高版本
    • 支持在不同屏幕分辨率下显示通知
    • 添加通知流方向
    • 允许删除缓冲区列表中的所有通知
       
© . All rights reserved.