扩展ToastNotifications:创建自定义通知类型与显示模板的完整教程
【免费下载链接】ToastNotificationsToast notifications for WPF allows you to create and display rich notifications in WPF applications. It's highly configurable with set of built-in options like positions, behaviours, themes and many others. It's extendable, it gives you possibility to create custom and interactive notifications in simply manner.项目地址: https://gitcode.com/gh_mirrors/to/ToastNotifications
ToastNotifications是一个功能强大的WPF通知库,它允许您在WPF应用程序中创建和显示丰富的通知。这个开源项目的核心优势在于其高度可扩展性,让开发者能够轻松创建自定义和交互式通知。在本终极指南中,我将向您展示如何充分利用ToastNotifications的扩展能力,创建完全自定义的通知类型和显示模板。🎯
为什么需要自定义Toast通知?
WPF应用程序中的通知系统对于用户体验至关重要。虽然ToastNotifications提供了内置的消息类型(如成功、错误、警告和信息),但在实际项目中,您可能需要更复杂的通知格式。比如:
- 带有确认/取消按钮的交互式通知
- 包含输入框的表单通知
- 自定义布局和样式的品牌化通知
- 集成第三方UI库(如MahApps.Metro)的通知
ToastNotifications的插件架构让这一切变得简单!✨
开始之前:项目准备
首先,您需要安装ToastNotifications核心包。打开NuGet包管理器控制台,运行以下命令:
Install-Package ToastNotifications如果您还需要预定义的消息类型,可以同时安装:
Install-Package ToastNotifications.Messages第一步:理解ToastNotifications的架构
ToastNotifications v2采用了清晰的分离架构:
- NotificationBase- 所有通知的基类,包含通知数据
- NotificationDisplayPart- 显示部分,控制通知的外观
- Notifier- 通知管理器,负责显示和生命周期管理
自定义通知的关键在于创建这两个组件的子类。让我们从最简单的自定义消息开始!
第二步:创建基础自定义通知类
在您的项目中创建一个新的C#类文件,比如CustomMessageNotification.cs。这个类将继承自NotificationBase并实现INotifyPropertyChanged接口:
using System.ComponentModel; using System.Runtime.CompilerServices; using ToastNotifications.Core; namespace YourApp.CustomNotifications { public class CustomMessageNotification : NotificationBase, INotifyPropertyChanged { private CustomMessageDisplayPart _displayPart; public override NotificationDisplayPart DisplayPart => _displayPart ?? (_displayPart = new CustomMessageDisplayPart(this)); public CustomMessageNotification(string title, string message, MessageOptions messageOptions) : base(message, messageOptions) { Title = title; Message = message; } private string _title; public string Title { get => _title; set { _title = value; OnPropertyChanged(); } } private string _message; public string Message { get => _message; set { _message = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }这个类包含了通知的核心数据:标题和消息内容。DisplayPart属性返回将用于显示此通知的UI组件。
第三步:设计自定义显示模板
现在创建显示部分。在WPF中,这通常是一个用户控件。右键单击项目,选择"添加"→"用户控件",命名为CustomMessageDisplayPart.xaml。
首先修改XAML文件,将基类从UserControl改为NotificationDisplayPart:
<core:NotificationDisplayPart x:Class="YourApp.CustomNotifications.CustomMessageDisplayPart" 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" xmlns:local="clr-namespace:YourApp.CustomNotifications" xmlns:core="clr-namespace:ToastNotifications.Core;assembly=ToastNotifications" mc:Ignorable="d" d:DesignHeight="80" d:DesignWidth="300" Background="#FF2D2D30" CornerRadius="5"> <Border BorderBrush="#FF007ACC" BorderThickness="2" CornerRadius="5"> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TextBlock Text="{Binding Title}" FontWeight="Bold" FontSize="14" Foreground="#FF007ACC" Margin="0,0,0,5"/> <TextBlock Grid.Row="1" Text="{Binding Message}" FontWeight="Light" Foreground="White" TextWrapping="Wrap"/> </Grid> </Border> </core:NotificationDisplayPart>然后修改代码隐藏文件:
using ToastNotifications.Core; namespace YourApp.CustomNotifications { public partial class CustomMessageDisplayPart : NotificationDisplayPart { public CustomMessageDisplayPart(CustomMessageNotification notification) { InitializeComponent(); Bind(notification); } } }注意构造函数中的Bind(notification)调用,这是将通知数据绑定到UI的关键步骤!🔗
第四步:创建扩展方法(可选但推荐)
为了让使用更简洁,创建一个扩展方法:
using ToastNotifications; namespace YourApp.CustomNotifications { public static class CustomMessageExtensions { public static void ShowCustomMessage(this Notifier notifier, string title, string message) { notifier.Notify<CustomMessageNotification>(() => new CustomMessageNotification(title, message, new MessageOptions())); } } }现在您可以使用更简洁的语法显示自定义通知:
notifier.ShowCustomMessage("操作成功", "您的文件已成功上传!");第五步:创建交互式通知(带按钮)
让我们创建一个更高级的示例 - 带有确认和取消按钮的通知:
using System; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Input; using ToastNotifications.Core; using YourApp.Utilities; // 假设您有RelayCommand类 namespace YourApp.CustomNotifications { public class ConfirmationNotification : NotificationBase, INotifyPropertyChanged { private ConfirmationDisplayPart _displayPart; private Action<ConfirmationNotification> _confirmAction; private Action<ConfirmationNotification> _cancelAction; public ICommand ConfirmCommand { get; set; } public ICommand CancelCommand { get; set; } public ConfirmationNotification(string message, Action<ConfirmationNotification> confirmAction, Action<ConfirmationNotification> cancelAction, MessageOptions messageOptions) : base(message, messageOptions) { Message = message; _confirmAction = confirmAction; _cancelAction = cancelAction; ConfirmCommand = new RelayCommand(x => _confirmAction(this)); CancelCommand = new RelayCommand(x => _cancelAction(this)); } public override NotificationDisplayPart DisplayPart => _displayPart ?? (_displayPart = new ConfirmationDisplayPart(this)); private string _message; public string Message { get => _message; set { _message = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }对应的显示模板:
<core:NotificationDisplayPart x:Class="YourApp.CustomNotifications.ConfirmationDisplayPart" 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" xmlns:local="clr-namespace:YourApp.CustomNotifications" xmlns:core="clr-namespace:ToastNotifications.Core;assembly=ToastNotifications" mc:Ignorable="d" d:DesignHeight="120" d:DesignWidth="350" Background="#FF2D2D30" CornerRadius="5"> <Border BorderBrush="#FFD84315" BorderThickness="2" CornerRadius="5"> <Grid Margin="15"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBlock Text="确认操作" FontWeight="Bold" FontSize="14" Foreground="#FFD84315" Margin="0,0,0,10"/> <TextBlock Grid.Row="1" Text="{Binding Message}" FontWeight="Light" Foreground="White" TextWrapping="Wrap" Margin="0,0,0,15"/> <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right"> <Button Content="取消" Command="{Binding CancelCommand}" Margin="0,0,10,0" Padding="12,6" Background="#FF757575" Foreground="White"/> <Button Content="确认" Command="{Binding ConfirmCommand}" Padding="12,6" Background="#FFD84315" Foreground="White"/> </StackPanel> </Grid> </Border> </core:NotificationDisplayPart>第六步:集成第三方UI库(MahApps.Metro示例)
如果您使用MahApps.Metro,可以轻松集成其样式:
using MahApps.Metro.Controls; using ToastNotifications.Core; namespace YourApp.CustomNotifications { public partial class MetroNotificationDisplayPart : NotificationDisplayPart { public MetroNotificationDisplayPart(MetroNotification notification) { InitializeComponent(); Bind(notification); } } }XAML中使用MahApps控件:
<core:NotificationDisplayPart x:Class="YourApp.CustomNotifications.MetroNotificationDisplayPart" 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" xmlns:local="clr-namespace:YourApp.CustomNotifications" xmlns:core="clr-namespace:ToastNotifications.Core;assembly=ToastNotifications" xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="350"> <controls:MetroWindow.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </controls:MetroWindow.Resources> <Grid> <controls:Tile Title="{Binding Title}" Content="{Binding Message}" Width="350" Height="100" HorizontalTitleAlignment="Center" VerticalTitleAlignment="Center" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/> </Grid> </core:NotificationDisplayPart>第七步:配置和使用Notifier
在主应用程序中配置Notifier:
using ToastNotifications; using ToastNotifications.Lifetime; using ToastNotifications.Position; using System.Windows; namespace YourApp { public partial class MainWindow : Window { private Notifier _notifier; public MainWindow() { InitializeComponent(); InitializeNotifier(); } private void InitializeNotifier() { _notifier = new Notifier(cfg => { cfg.PositionProvider = new WindowPositionProvider( parentWindow: Application.Current.MainWindow, corner: Corner.BottomRight, offsetX: 10, offsetY: 10); cfg.LifetimeSupervisor = new TimeAndCountBasedLifetimeSupervisor( notificationLifetime: TimeSpan.FromSeconds(5), maximumNotificationCount: MaximumNotificationCount.FromCount(10)); cfg.Dispatcher = Application.Current.Dispatcher; }); } private void ShowCustomNotification_Click(object sender, RoutedEventArgs e) { // 使用自定义消息 _notifier.ShowCustomMessage("系统通知", "操作已完成!"); // 或者使用交互式通知 _notifier.Notify<ConfirmationNotification>(() => new ConfirmationNotification( "确定要删除这个文件吗?", notification => { // 确认操作 MessageBox.Show("文件已删除"); _notifier.Hide(notification); }, notification => { // 取消操作 _notifier.Hide(notification); }, new MessageOptions())); } protected override void OnClosed(EventArgs e) { _notifier?.Dispose(); base.OnClosed(e); } } }最佳实践和高级技巧
1. 主题和样式统一
确保自定义通知与应用程序的整体设计语言保持一致。您可以在App.xaml中定义全局样式:
<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/ToastNotifications.Messages;component/Themes/Default.xaml" /> <!-- 您的自定义样式 --> </ResourceDictionary.MergedDictionaries> <!-- 自定义通知样式 --> <Style TargetType="local:CustomMessageDisplayPart"> <Setter Property="Background" Value="{DynamicResource PrimaryBackground}" /> <Setter Property="Foreground" Value="{DynamicResource PrimaryForeground}" /> </Style> </ResourceDictionary> </Application.Resources>2. 动画效果增强
为通知添加平滑的显示/隐藏动画:
<core:NotificationDisplayPart.Resources> <Storyboard x:Key="ShowAnimation"> <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.3"/> <ThicknessAnimation Storyboard.TargetProperty="Margin" From="0,20,0,0" To="0" Duration="0:0:0.3"/> </Storyboard> <Storyboard x:Key="HideAnimation"> <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.3"/> </Storyboard> </core:NotificationDisplayPart.Resources>3. 响应式设计
确保通知在不同屏幕尺寸下都能良好显示:
<VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="Normal"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="0"/> </VisualState.StateTriggers> <VisualState.Setters> <Setter TargetName="ContentGrid" Property="Width" Value="300"/> </VisualState.Setters> </VisualState> <VisualState x:Name="Wide"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="800"/> </VisualState.StateTriggers> <VisualState.Setters> <Setter TargetName="ContentGrid" Property="Width" Value="400"/> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>4. 性能优化
- 使用
VirtualizingStackPanel处理大量通知 - 实现
IDisposable接口及时释放资源 - 使用弱引用避免内存泄漏
调试和故障排除
常见问题:
通知不显示
- 检查
Dispatcher是否正确设置 - 确认
PositionProvider配置正确 - 验证通知生命周期设置
- 检查
数据绑定失败
- 确保通知类实现
INotifyPropertyChanged - 检查XAML中的绑定路径是否正确
- 确认
Bind(notification)在构造函数中被调用
- 确保通知类实现
样式不生效
- 检查资源字典引用
- 确认样式选择器正确
- 验证合并的资源字典顺序
调试技巧:
- 使用
Snoop或Live Visual Tree检查WPF可视化树 - 在通知构造函数中添加日志记录
- 使用
PresentationTraceSources.TraceLevel调试数据绑定
总结
通过ToastNotifications的扩展机制,您可以创建几乎任何类型的通知。从简单的文本通知到复杂的交互式表单,ToastNotifications提供了强大而灵活的框架。关键步骤包括:
- 创建继承自
NotificationBase的通知数据类 - 创建继承自
NotificationDisplayPart的显示模板 - 实现数据绑定和属性通知
- 创建扩展方法简化使用
- 配置Notifier实例
ToastNotifications的模块化设计让扩展变得直观而强大。无论是简单的状态通知还是复杂的用户交互,您都可以构建出符合应用程序需求的完美通知系统。🚀
记住,良好的通知系统不仅能提供信息,还能增强用户体验。花时间设计美观、一致且有用的通知,您的用户会感谢您的!
现在,开始创建您自己的自定义Toast通知吧!如果您遇到任何问题,可以参考项目中的示例代码:Src/Examples/CustomNotificationsExample/ 获取更多灵感。💡
【免费下载链接】ToastNotificationsToast notifications for WPF allows you to create and display rich notifications in WPF applications. It's highly configurable with set of built-in options like positions, behaviours, themes and many others. It's extendable, it gives you possibility to create custom and interactive notifications in simply manner.项目地址: https://gitcode.com/gh_mirrors/to/ToastNotifications
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考