WPF 自定义MessageBox系列
第一节 简单MessageBox
第二节 倒计时MessageBox
第三节 自定义按钮的MessageBox
第四节 界面操作分离的MessageBox(本节)
第五节 替换系统的MessageBox
文章目录
前言
本篇是上一篇《C# wpf 实现自定义按钮及Toast的MessageBox》的优化,将MessageBox的操作逻辑与界面完全分离了,这样做的好处是在于,界面的随意切换,操作逻辑可以不用改动或重写。
一、如何分离?
1、定义DataContext对象
定义一个DataContext对象,将需要的数据全部定义在DataContext对象中,通过INotifyPropertyChanged实现双向通知。
MessageBox需要的属性有:
/// <summary>
/// 消息框的标题
/// </summary>
public string Title{get;get;}
/// <summary>
/// 消息框的文本内容
/// </summary>
public string Context{get;get;}
/// <summary>
/// Yes按钮的文本
/// </summary>
public string YesText{get;get;}
/// <summary>
/// No按钮的文本
/// </summary>
public string NoText{get;get;}
/// <summary>
/// Yes选项剩余时间
/// </summary>
public TimeSpan? YesLeftTime{get;get;}
/// <summary>
/// No选项剩余时间
/// </summary>
public TimeSpan? NoLeftTime{get;get;}
/// <summary>
/// No按钮命令
/// </summary>
public ICommand NoCommand{get;get;}
/// <summary>
/// Yes按钮命令
/// </summary>
public ICommand YesCommand{get;get;}
/// <summary>
///Cancel按钮命令
/// </summary>
public ICommand CancelCommand{get;get;}
2、绑定属性
在xaml中实现消息框的样式,并绑定上述属性。上述属性不需要全部绑定可以根据需要自行选择,比如只需要定义一个Toast则只绑定Context即可。
<TextBlock Text="{Binding Context}" />
3、泛型调用
将MessageBox的操作方法定义成泛型,根据具体传入的MessageBox与DataContext对象关联后再显示。比如将方法定义在MessageBoxHelper类中:
MessageBox窗口
MessageBoxHelper.ShowDialog<MessageBox>("Ensure?", "Yes", "No",TimeSpan.FromSeconds(10), null);
Toast窗口
MessageBoxHelper.Toast<Toast>("Hello word",TimeSpan.FromSeconds(10));
二、代码
1、接口设计
代码的逻辑关系:
上图对应到代码:
将所有操作逻辑封装在MessageBoxHelper中:
namespace WpfApp1
{
/// <summary>
/// 结果按钮
/// </summary>
public enum MessageBoxResultButton
{
Yes,
No,
Cancel
}
/// <summary>
/// 结果
/// </summary>
public class MessageBoxResult
{
/// <summary>
/// 结果按钮
/// </summary>
public MessageBoxResultButton Button { get; set; }
/// <summary>
/// Yes剩余时间
/// </summary>
public TimeSpan? YesLeftTime { get; set; }
/// <summary>
/// No剩余时间
/// </summary>
public TimeSpan? NoLeftTime { get; set; }
}
/// <summary>
/// 业务数据对象
/// </summary>
public class MessageBoxDataContext : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// 消息框的标题
/// </summary>
public string Title{ set; get; }
/// <summary>
/// 消息框的文本内容
/// </summary>
public string Context{ set; get; }
/// <summary>
/// Yes按钮的文本
/// </summary>
public string YesText{ set; get; }
/// <summary>
/// No按钮的文本
/// </summary>
public string NoText{ set; get; }
/// <summary>
/// Yes选项剩余时间
/// </summary>
public TimeSpan? YesLeftTime{ set; get; }
/// <summary>
/// No选项剩余时间
/// </summary>
public TimeSpan? NoLeftTime{ set; get; }
/// <summary>
/// No按钮命令
/// </summary>
public ICommand NoCommand{ set; get; }
/// <summary>
/// Yes按钮命令
/// </summary>
public ICommand YesCommand{ set; get; }
/// <summary>
///Cancel按钮命令
/// </summary>
public ICommand CancelCommand{ set; get; }
/// <summary>
///结果
/// </summary>
public MessageBoxResult Result { internal set; get; }
}
public class MessageBoxHelper
{
/// <summary>
///toast弹出消息
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="context">显示内容</param>
/// <param name="stayTime">停留时间</param>
public static void Toast<T>(string context, TimeSpan stayTime) where T : Window, new();
/// <summary>
/// 显示消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="context">显示内容</param>
/// <returns>结果</returns>
public static MessageBoxResult ShowDialog<T>(string context) where T : Window, new();
/// <summary>
/// 显示消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <returns>结果</returns>
public static MessageBoxResult ShowDialog<T>(string title, string context) where T : Window, new();
/// <summary>
/// 显示消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <returns>结果</returns>
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText) where T : Window, new();
/// <summary>
/// 显示消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="isCancelable">是否显示取消按钮</param>
/// <returns>结果</returns>
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText, bool isCancelable) where T : Window, new();
/// <summary>
/// 显示消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="noText">no按钮的文本</param>
/// <returns>结果</returns>
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText, string noText) where T : Window, new();
/// <summary>
/// 显示消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="noText">no按钮的文本</param>
/// <param name="isCancelable">是否显示取消按钮</param>
/// <returns>结果</returns>
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText, string noText, bool isCancelable) where T : Window, new();
/// <summary>
/// 显示消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="context">显示内容</param>
/// <param name="yestCountDown">yes按钮倒计时</param>
/// <param name="noCountDown">no按钮倒计时</param>
/// <returns>结果</returns>
public static MessageBoxResult ShowDialog<T>(string context, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new();
/// <summary>
/// 显示消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="noText">no按钮的文本</param>
/// <param name="yestCountDown">yes按钮倒计时</param>
/// <param name="noCountDown">no按钮倒计时</param>
/// <returns>结果</returns>
public static MessageBoxResult ShowDialog<T>(string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new();
/// <summary>
/// 显示消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="noText">no按钮的文本</param>
/// <param name="yestCountDown">yes按钮倒计时</param>
/// <param name="noCountDown">no按钮倒计时</param>
/// <returns>结果</returns>
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new();
/// 显示消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="noText">no按钮的文本</param>
/// <param name="yestCountDown">yes按钮倒计时</param>
/// <param name="noCountDown">no按钮倒计时</param>
/// <param name="isCancelable">是否显示取消按钮</param>
/// <returns>结果</returns>
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown, bool isCancelable) where T : Window, new();
/// <summary>
/// 获取结果,通常和MessageBoxHelper.Create<T>配合使用
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="messageBox">MessageBoxHelper.Create<T>返回的对象</param>
/// <returns>结果</returns>
public static MessageBoxResult GetResult<T>(T messageBox) where T : Window, new();
/// <summary>
/// 创建消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="context">显示内容</param>
/// <returns>消息框对象</returns>
public static T Create<T>(string context) where T : Window, new();
/// <summary>
/// 创建消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <returns>消息框对象</returns>
public static T Create<T>(string title, string context) where T : Window, new();
/// <summary>
/// 创建消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <returns>消息框对象</returns>
public static T Create<T>(string title, string context, string yesText) where T : Window, new();
/// <summary>
/// 创建消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="isCancelable">是否显示取消按钮</param>
/// <returns>消息框对象</returns>
public static T Create<T>(string title, string context, string yesText, bool isCancelable) where T : Window, new();
/// <summary>
/// 创建消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="noText">no按钮的文本</param>
/// <returns>消息框对象</returns>
public static T Create<T>(string title, string context, string yesText, string noText) where T : Window, new();
/// <summary>
/// 创建消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="noText">no按钮的文本</param>
/// <param name="isCancelable">是否显示取消按钮</param>
/// <returns>消息框对象</returns>
public static T Create<T>(string title, string context, string yesText, string noText, bool isCancelable) where T : Window, new();
/// <summary>
/// 创建消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="context">显示内容</param>
/// <param name="yestCountDown">yes按钮倒计时</param>
/// <param name="noCountDown">no按钮倒计时</param>
/// <returns>消息框对象</returns>
public static T Create<T>(string context, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new();
/// <summary>
/// 创建消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="noText">no按钮的文本</param>
/// <param name="yestCountDown">yes按钮倒计时</param>
/// <param name="noCountDown">no按钮倒计时</param>
/// <returns>消息框对象</returns>
public static T Create<T>(string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new();
/// <summary>
/// 创建消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="noText">no按钮的文本</param>
/// <param name="yestCountDown">yes按钮倒计时</param>
/// <param name="noCountDown">no按钮倒计时</param>
/// <returns>消息框对象</returns>
public static T Createg<T>(string title, string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new();
/// <summary>
/// 创建消息框
/// </summary>
/// <typeparam name="T">绑定MessageBoxDataContext属性的窗口</typeparam>
/// <param name="title">标题</param>
/// <param name="context">显示内容</param>
/// <param name="yesText">yes按钮的文本</param>
/// <param name="noText">no按钮的文本</param>
/// <param name="yestCountDown">yes按钮倒计时</param>
/// <param name="noCountDown">no按钮倒计时</param>
/// <param name="isCancelable">是否显示取消按钮</param>
/// <returns>消息框对象</returns>
public static T Create<T>(string title, string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown, bool isCancelable) where T : Window, new();
}
}
2、完整代码
https://download.csdn.net/download/u013113678/85477733
三、实例
1、Toast
(1)界面代码
<Window x:Class="WpfApp1.Toast"
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:WpfApp1"
mc:Ignorable="d"
Title="Toast"
AllowsTransparency="True"
Background="Transparent"
ResizeMode="NoResize"
ShowInTaskbar="False"
Topmost="True"
WindowStartupLocation="CenterScreen"
Width="400"
Height="120"
WindowStyle="None"
>
<Grid>
<Border Margin="10" Background="White" CornerRadius="10" >
<Border.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.5"/>
</Border.Effect>
<Grid Margin="20">
<StackPanel VerticalAlignment="Center">
<!--只需绑定Context-->
<TextBlock Text="{Binding Context}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" Foreground="Gray"/>
</StackPanel>
</Grid>
</Border>
</Grid>
</Window>
(2)调用方法
MessageBoxHelper.Toast<Toast>("Hello word!", TimeSpan.FromSeconds(3));
(3)效果预览
2、简单MessageBox
(1)界面代码
<Window x:Class="WpfApp1.MessageBoxSimple"
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:WpfApp1"
mc:Ignorable="d"
Title="MessageBoxSimple"
AllowsTransparency="True"
Background="Transparent"
ResizeMode="NoResize"
ShowInTaskbar="False"
Topmost="True"
WindowStartupLocation="CenterScreen"
Width="600"
Height="260"
WindowStyle="None">
<Grid>
<Border Margin="10" Background="White" >
<Border.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.5"/>
</Border.Effect>
<Grid Margin="20">
<!--绑定Context-->
<TextBlock Margin="0,0,0,40" Text="{Binding Context}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" Foreground="Gray"/>
<StackPanel VerticalAlignment="Bottom" Orientation="Horizontal" HorizontalAlignment="Center" >
<!--绑定NoCommand命令-->
<Button Height="64" Width="144" Cursor="Hand" Command="{Binding NoCommand}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="White" BorderBrush="#cccccc" >
<Border.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.2"/>
</Border.Effect>
<!--绑定no文本NoText,也可以不绑定,直接使用页面上的文本-->
<TextBlock Name="text" Text="{Binding NoText}" FontSize="24" Foreground="Gray" HorizontalAlignment="Center" VerticalAlignment="Center">
</TextBlock>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<!--绑定YesCommand命令-->
<Button Margin="30,0,0,0" Height="64" Width="144" Cursor="Hand" Command="{Binding YesCommand}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Gray" >
<Border.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.2"/>
</Border.Effect>
<!--绑定yes文本YesText,也可以不绑定,直接使用页面上的文本-->
<TextBlock Name="text" Text="{Binding YesText}" FontSize="24" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center">
</TextBlock>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</StackPanel>
</Grid>
</Border>
</Grid>
</Window>
(2)调用方法
var r = MessageBoxHelper.ShowDialog<MessageBoxSimple>(null,"Ensure?", "Yes", "No");
if (r.Button == MessageBoxResultButton.Yes)
{
//选择了Yes
}
else if (r.Button == MessageBoxResultButton.No)
{
//选择了No
}
(3)效果预览
3、完整MessageBox
(1)界面代码
略,在完整代码中。
(2)调用方法及效果预览
Toast框
MessageBoxHelper.Toast<MessageBox>("Toast框", TimeSpan.FromSeconds(3));
OK框
MessageBoxHelper.ShowDialog<MessageBox>(null, "OK框", "OK");
OK倒计时框
MessageBoxHelper.ShowDialog<MessageBox>(null, "OK倒计时框", "OK", null, TimeSpan.FromSeconds(10), null);
YesNo框
var r=MessageBoxHelper.ShowDialog<MessageBox>(null, "YesNo框", "Yes", "No");
if (r.Button == MessageBoxResultButton.Yes)
{
//选择了Yes
}
else if (r.Button == MessageBoxResultButton.No)
{
//选择了No
}
YesNo倒计时框
var r=MessageBoxHelper.ShowDialog<MessageBox>(null, "YesNo倒计时框", "Yes", "No", TimeSpan.FromSeconds(10),null);
if (r.Button == MessageBoxResultButton.Yes)
{
//选择了Yes
}
else if (r.Button == MessageBoxResultButton.No)
{
//选择了No
}
带标题栏OK框
MessageBoxHelper.ShowDialog<MessageBox>("标题", "带标题栏OK框", "OK",null);
带标题栏YesNo框
var r=MessageBoxHelper.ShowDialog<MessageBox>("标题", "带标题栏YesNo框", "Yes", "No");
if (r.Button == MessageBoxResultButton.Yes)
{
//选择了Yes
}
else if (r.Button == MessageBoxResultButton.No)
{
//选择了No
}
可关闭YesNo框
var r=MessageBoxHelper.ShowDialog<MessageBox>("标题", "可关闭YesNo框", "Yes", "No", true);
if (r.Button == MessageBoxResultButton.Yes)
{
//选择了Yes
}
else if (r.Button == MessageBoxResultButton.No)
{
//选择了No
}
else if (r.Button == MessageBoxResultButton.Cancel)
{
//关闭了窗口
}
可关闭倒计时框
var r=MessageBoxHelper.ShowDialog<MessageBox>("标题", "可关闭倒计时框", "Yes", "No", null, TimeSpan.FromSeconds(10), true);
if (r.Button == MessageBoxResultButton.Yes)
{
//选择了Yes
}
else if (r.Button == MessageBoxResultButton.No)
{
//选择了No
}
else if (r.Button == MessageBoxResultButton.Cancel)
{
//关闭了窗口
}
总结
操作与界面分离后,方便了界面的灵活设计,在不同的项目只需要定义MessageBox的界面即可,操作逻辑直接使用MessageBoxHelper,减少了造轮子。