本篇是上一篇《C# wpf 实现自定义按钮及Toast的MessageBox》的优化,将MessageBox的操作逻辑与界面完全分离了,这样做的好处是在于,界面的随意切换,操作逻辑可以不用改动或重写。
定义一个DataContext对象,将需要的数据全部定义在DataContext对象中,通过INotifyPropertyChanged实现双向通知。
MessageBox需要的属性有:
///
/// 消息框的标题
///
public string Title{
get;get;}
///
/// 消息框的文本内容
///
public string Context{
get;get;}
///
/// Yes按钮的文本
///
public string YesText{
get;get;}
///
/// No按钮的文本
///
public string NoText{
get;get;}
///
/// Yes选项剩余时间
///
public TimeSpan? YesLeftTime{
get;get;}
///
/// No选项剩余时间
///
public TimeSpan? NoLeftTime{
get;get;}
///
/// No按钮命令
///
public ICommand NoCommand{
get;get;}
///
/// Yes按钮命令
///
public ICommand YesCommand{
get;get;}
///
///Cancel按钮命令
///
public ICommand CancelCommand{
get;get;}
在xaml中实现消息框的样式,并绑定上述属性。上述属性不需要全部绑定可以根据需要自行选择,比如只需要定义一个Toast则只绑定Context即可。
<TextBlock Text="{Binding Context}" />
将MessageBox的操作方法定义成泛型,根据具体传入的MessageBox与DataContext对象关联后再显示。比如将方法定义在MessageBoxHelper类中:
MessageBox窗口
MessageBoxHelper.ShowDialog<MessageBox>("Ensure?", "Yes", "No",TimeSpan.FromSeconds(10), null);
Toast窗口
MessageBoxHelper.Toast<Toast>("Hello word",TimeSpan.FromSeconds(10));
将所有操作逻辑封装在MessageBoxHelper中:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
namespace WpfApp1
{
///
/// 结果按钮
///
public enum MessageBoxResultButton
{
Yes,
No,
Cancel
}
///
/// 结果
///
public class MessageBoxResult
{
///
/// 结果按钮
///
public MessageBoxResultButton Button {
get; set; }
///
/// Yes剩余时间
///
public TimeSpan? YesLeftTime {
get; set; }
///
/// No剩余时间
///
public TimeSpan? NoLeftTime {
get; set; }
}
///
/// 业务数据对象
///
public class MessageBoxDataContext : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
///
/// 消息框的标题
///
public string Title
{
get {
return _title; }
set {
_title = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Title")); }
}
///
/// 消息框的文本内容
///
public string Context
{
get {
return _context; }
set {
_context = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Context")); }
}
///
/// Yes按钮的文本
///
public string YesText
{
get {
return _yesText; }
set {
_yesText = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("YesText")); }
}
///
/// No按钮的文本
///
public string NoText
{
get {
return _noText; }
set {
_noText = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NoText")); }
}
///
/// Yes选项剩余时间
///
public TimeSpan? YesLeftTime
{
get {
return _yesLeftTime; }
set {
_yesLeftTime = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("YesLeftTime")); }
}
///
/// No选项剩余时间
///
public TimeSpan? NoLeftTime
{
get {
return _noLeftTime; }
set {
_noLeftTime = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NoLeftTime")); }
}
///
/// No按钮命令
///
public ICommand NoCommand
{
get {
return _noCommand; }
set {
_noCommand = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NoCommand")); }
}
///
/// Yes按钮命令
///
public ICommand YesCommand
{
get {
return _yesCommand; }
set {
_yesCommand = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("YesCommand")); }
}
///
///Cancel按钮命令
///
public ICommand CancelCommand
{
get {
return _cancleCommand; }
set {
_cancleCommand = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CancelCommand")); }
}
///
///结果
///
public MessageBoxResult Result {
internal set; get; }
///
/// 倒计时的时钟
///
internal DispatcherTimer Timer {
set; get; }
string _title = "tips";
string _context = "Ensure?";
string _yesText = "Yes";
string _noText = "No";
TimeSpan? _yesLeftTime;
TimeSpan? _noLeftTime;
ICommand _noCommand;
ICommand _yesCommand;
ICommand _cancleCommand;
}
public class MessageBoxHelper
{
class Command : ICommand
{
Action<object> _action;
public Command(Action<object> action)
{
_action = action;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_action(parameter);
}
}
///
///toast弹出消息
///
/// 绑定MessageBoxDataContext属性的窗口
/// 显示内容
/// 停留时间
public static void Toast<T>(string context, TimeSpan stayTime) where T : Window, new()
{
App.Current.Dispatcher.BeginInvoke(new Action(() =>
{
ShowDialog<T>(null, context, null, null, stayTime, null, false);
}));
}
///
/// 显示消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 显示内容
/// 结果
public static MessageBoxResult ShowDialog<T>(string context) where T : Window, new()
{
return ShowDialog<T>(null, context, "确定", null, null, null, false);
}
///
/// 显示消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// 结果
public static MessageBoxResult ShowDialog<T>(string title, string context) where T : Window, new()
{
return ShowDialog<T>(title, context, "确定", null, null, null, false);
}
///
/// 显示消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// 结果
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText) where T : Window, new()
{
return ShowDialog<T>(title, context, yesText, null, null, null, false);
}
///
/// 显示消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// 是否显示取消按钮
/// 结果
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText, bool isCancelable) where T : Window, new()
{
return ShowDialog<T>(title, context, yesText, null, null, null, isCancelable);
}
///
/// 显示消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// no按钮的文本
/// 结果
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText, string noText) where T : Window, new()
{
return ShowDialog<T>(title, context, yesText, noText, null, null, false);
}
///
/// 显示消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// no按钮的文本
/// 是否显示取消按钮
/// 结果
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText, string noText, bool isCancelable) where T : Window, new()
{
return ShowDialog<T>(title, context, yesText, noText, null, null, isCancelable);
}
///
/// 显示消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 显示内容
/// yes按钮倒计时
/// no按钮倒计时
/// 结果
public static MessageBoxResult ShowDialog<T>(string context, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new()
{
return ShowDialog<T>(null, context, null, null, yestCountDown, noCountDown, false);
}
///
/// 显示消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 显示内容
/// yes按钮的文本
/// no按钮的文本
/// yes按钮倒计时
/// no按钮倒计时
/// 结果
public static MessageBoxResult ShowDialog<T>(string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new()
{
return ShowDialog<T>(null, context, yesText, noText, yestCountDown, noCountDown, false);
}
///
/// 显示消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// no按钮的文本
/// yes按钮倒计时
/// no按钮倒计时
/// 结果
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new()
{
return ShowDialog<T>(title, context, yesText, noText, yestCountDown, noCountDown, false);
}
///
/// 显示消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// no按钮的文本
/// yes按钮倒计时
/// no按钮倒计时
/// 是否显示取消按钮
/// 结果
public static MessageBoxResult ShowDialog<T>(string title, string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown, bool isCancelable) where T : Window, new()
{
var mb = Create<T>(title, context, yesText, noText, yestCountDown, noCountDown, isCancelable);
mb.ShowDialog();
return GetResult(mb);
}
///
/// 获取结果,通常和MessageBoxHelper.Create配合使用
///
/// 绑定MessageBoxDataContext属性的窗口
/// MessageBoxHelper.Create返回的对象
/// 结果
public static MessageBoxResult GetResult<T>(T messageBox) where T : Window, new()
{
var mc = messageBox.DataContext as MessageBoxDataContext;
if (mc != null)
{
return mc.Result;
}
return null;
}
///
/// 创建消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 显示内容
/// 消息框对象
public static T Create<T>(string context) where T : Window, new()
{
return Create<T>(null, context, "确定", null, null, null, false);
}
///
/// 创建消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// 消息框对象
public static T Create<T>(string title, string context) where T : Window, new()
{
return Create<T>(title, context, "确定", null, null, null, false);
}
///
/// 创建消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// 消息框对象
public static T Create<T>(string title, string context, string yesText) where T : Window, new()
{
return Create<T>(title, context, yesText, null, null, null, false);
}
///
/// 创建消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// 是否显示取消按钮
/// 消息框对象
public static T Create<T>(string title, string context, string yesText, bool isCancelable) where T : Window, new()
{
return Create<T>(title, context, yesText, null, null, null, isCancelable);
}
///
/// 创建消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// no按钮的文本
/// 消息框对象
public static T Create<T>(string title, string context, string yesText, string noText) where T : Window, new()
{
return Create<T>(title, context, yesText, noText, null, null, false);
}
///
/// 创建消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// no按钮的文本
/// 是否显示取消按钮
/// 消息框对象
public static T Create<T>(string title, string context, string yesText, string noText, bool isCancelable) where T : Window, new()
{
return Create<T>(title, context, yesText, noText, null, null, isCancelable);
}
///
/// 创建消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 显示内容
/// yes按钮倒计时
/// no按钮倒计时
/// 消息框对象
public static T Create<T>(string context, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new()
{
return Create<T>(null, context, null, null, yestCountDown, noCountDown, false);
}
///
/// 创建消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 显示内容
/// yes按钮的文本
/// no按钮的文本
/// yes按钮倒计时
/// no按钮倒计时
/// 消息框对象
public static T Create<T>(string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new()
{
return Create<T>(null, context, yesText, noText, yestCountDown, noCountDown, false);
}
///
/// 创建消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// no按钮的文本
/// yes按钮倒计时
/// no按钮倒计时
/// 消息框对象
public static T Createg<T>(string title, string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown) where T : Window, new()
{
return Create<T>(title, context, yesText, noText, yestCountDown, noCountDown, false);
}
///
/// 创建消息框
///
/// 绑定MessageBoxDataContext属性的窗口
/// 标题
/// 显示内容
/// yes按钮的文本
/// no按钮的文本
/// yes按钮倒计时
/// no按钮倒计时
/// 是否显示取消按钮
/// 消息框对象
public static T Create<T>(string title, string context, string yesText, string noText, TimeSpan? yestCountDown, TimeSpan? noCountDown, bool isCancelable) where T : Window, new()
{
T mb = new T();
MessageBoxDataContext mc = new MessageBoxDataContext();
bool isLegal = false;
mb.DataContext = mc;
mc.Title = title;
mc.Context = context;
mc.YesText = yesText;
mc.NoText = noText;
mc.YesLeftTime = yestCountDown;
mc.NoLeftTime = noCountDown;
mc.YesCommand = new Command((o) =>
{
mc.Result = new MessageBoxResult() {
Button = MessageBoxResultButton.Yes, YesLeftTime = mc.YesLeftTime, NoLeftTime = mc.NoLeftTime };
isLegal = true;
mb.Close();
});
mc.NoCommand = new Command((o) =>
{
mc.Result = new MessageBoxResult() {
Button = MessageBoxResultButton.No, YesLeftTime = mc.YesLeftTime, NoLeftTime = mc.NoLeftTime };
isLegal = true;
mb.Close();
});
if (isCancelable)
{
mc.CancelCommand = new Command((o) =>
{
mc.Result = new MessageBoxResult() {
Button = MessageBoxResultButton.Cancel, YesLeftTime = mc.YesLeftTime, NoLeftTime = mc.NoLeftTime };
isLegal = true;
mb.Close();
});
}
mb.Loaded += (s, e) =>
{
if (mc.YesLeftTime != null || mc.NoLeftTime != null)
{
mc.Timer = new DispatcherTimer();
mc.Timer.Interval = TimeSpan.FromSeconds(1);
mc.Timer.Tick += (S, E) =>
{
if (mc.YesLeftTime != null)
{
mc.YesLeftTime = mc.YesLeftTime.Value.Add(-TimeSpan.FromSeconds(1));
if (mc.YesLeftTime.Value.TotalSeconds < 1)
{
mc.Timer.Stop();
mc.YesCommand.Execute(null);
}
}
if (mc.NoLeftTime != null)
{
mc.NoLeftTime = mc.NoLeftTime.Value.Add(-TimeSpan.FromSeconds(1));
if (mc.NoLeftTime.Value.TotalSeconds < 1)
{
mc.Timer.Stop();
mc.NoCommand.Execute(null);
}
}
};
mc.Timer.Start();
}
};
mb.Closing += (s, e) =>
{
e.Cancel = !isLegal;
};
mb.Closed += (s, e) =>
{
if (mc.Timer != null && mc.Timer.IsEnabled)
{
mc.Timer.Stop();
}
};
return mb;
}
}
}
<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">
<TextBlock Text="{Binding Context}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" Foreground="Gray"/>
StackPanel>
Grid>
Border>
Grid>
Window>
MessageBoxHelper.Toast<Toast>("Hello word!", TimeSpan.FromSeconds(3));
<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">
<TextBlock Margin="0,0,0,40" Text="{Binding Context}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" Foreground="Gray"/>
<StackPanel VerticalAlignment="Bottom" Orientation="Horizontal" HorizontalAlignment="Center" >
<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>
<TextBlock Name="text" Text="{Binding NoText}" FontSize="24" Foreground="Gray" HorizontalAlignment="Center" VerticalAlignment="Center">
TextBlock>
Border>
ControlTemplate>
Button.Template>
Button>
<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>
<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>
var r = MessageBoxHelper.ShowDialog<MessageBoxSimple>(null,"Ensure?", "Yes", "No");
if (r.Button == MessageBoxResultButton.Yes)
{
//选择了Yes
}
else if (r.Button == MessageBoxResultButton.No)
{
//选择了No
}
https://download.csdn.net/download/u013113678/34203243
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
}
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,减少了造轮子。