赞
踩
本文通过一个简单的demo示例,介绍了MaterialDesign在wpf应用程序中的使用,实现wpf的mvvm,并封装了MaterialDesign酷炫的弹窗对话框,在此做一些总结,并在文章的最后分享完整源码。
demo效果如下:
在VS2022中,基于.net6.0创建wpf项目,在Nuget包管理器输入“MaterialDesign”,安装MaterialDesign。
在App.xaml文件中添加MaterialDesign的资源字典
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
<!--<materialDesign:BundledTheme BaseTheme="Dark" PrimaryColor="DeepPurple" SecondaryColor="Lime" />-->
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
编译一下,之后在MainWindow.xaml中随便加一些控件(比如Button),就能看到MaterialDesign的样式了。本demo的主界面设计如下:
说明:在MainWindow的设计中,使用了“<md:DialogHost Identifier=“Root”>”,其中md是对MaterialDesign的命名空间的申明,这个xaml意思是将此窗口作为对话框的DialogHost,并用“Root”命名作为唯一识别。此名称将传递到对话框中,告诉对话框悬停在哪个DialogHost上。在实际应用中,可以有多个DialogHost,取不同的名称即可。
在不使用第三方mvvm框架的情况下,我对INotifyPropertyChanged(绑定UI显示)和ICommand(绑定命令)进行了简单封装。如下:
internal class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string property=null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
internal class DelegateCommand : ICommand { public DelegateCommand(Action<object> action) { _action = action; } private Action<object> _action; public event EventHandler? CanExecuteChanged; public bool CanExecute(object? parameter) { return true; } public void Execute(object? parameter) { _action?.Invoke(parameter); } }
一般在cs程序中最常用的对话框就是信息提示框、确认对话框、信息输入框、等待进度提示框等。这里我进行了封装,信息输入框(InputView)、信息提示/确认对话框(MessageView)、转圈等待提示框(CurcularProgressView),其中MessageView既可以做信息提示框,也可以做确认询问框。
新建一个用户控件,取名“InputView”,以此作为信息输入框。界面设计如下:
其中,输入框的标题、提示语、默认值,都是可以通过传入参数配置的。
新建一个用户控件,取名“MessageView”,以此作为信息提示/确认对话框。界面设计如下:
其中,对话框的标题、提示语、Cancel按钮是否可见(是否询问对话框),都是可以通过传入参数配置的。
为对话框的参数传递及数据回传,设计专门的类
internal enum CommonDialogButton { Cancel=0, //取消 Ok=1 //确认 } /// <summary> /// 对话框返回的结果 /// </summary> internal class CommonDialogResult { /// <summary> /// 点击了哪个按钮 /// </summary> public CommonDialogButton Button { get; set; } /// <summary> /// 回传的数据 /// </summary> public object Data { get; set; } } /// <summary> /// 对话框的参数 /// </summary> public class CommonDialogParams { /// <summary> /// 对话框悬停的Host名称 /// </summary> public string DialogHost { get; set; } = "Root"; /// <summary> /// 对话框的标题 /// </summary> public string DialogTitle { get; set; } /// <summary> /// 对话框的提示语 /// </summary> public string DialogTipText { get; set; } /// <summary> /// 如果是输入框,则可设置默认值 /// </summary> public string DefaultText { get; set; } /// <summary> /// 是否是询问对话框 /// </summary> public bool IsQuestion { get; set; } }
internal class InputViewModel: ViewModelBase { public InputViewModel() { SureCommand = new DelegateCommand(Sure); CancelCommand = new DelegateCommand(Cancel); } private string title; public string Title { get { return title; } set { title = value; RaisePropertyChanged(); } } private string tipText; public string TipText { get { return tipText; } set { tipText = value; RaisePropertyChanged(); } } private string inputString; public string InputString { get { return inputString; } set { inputString = value; RaisePropertyChanged(); } } private void Cancel(object p) { if (DialogHost.IsDialogOpen(DialogHostName)) DialogHost.Close(DialogHostName, new CommonDialogResult() {Button=CommonDialogButton.Cancel,Data=null }); } private void Sure(object p) { if (string.IsNullOrEmpty(InputString)) return; if (DialogHost.IsDialogOpen(DialogHostName)) { DialogHost.Close(DialogHostName, new CommonDialogResult() { Button = CommonDialogButton.Ok, Data = inputString }); } } private string DialogHostName { get; set; } = "Root"; public DelegateCommand SureCommand { get; set; } public DelegateCommand CancelCommand { get; set; } public void InitParams(CommonDialogParams p) { DialogHostName = p.DialogHost; Title = p.DialogTitle; TipText = p.DialogTipText; InputString = p.DefaultText; } }
internal class MessageViewModel:ViewModelBase { public MessageViewModel() { SureCommand = new DelegateCommand(Sure); CancelCommand = new DelegateCommand(Cancel); } private string title; public string Title { get { return title; } set { title = value; RaisePropertyChanged(); } } private Visibility visibility = Visibility.Visible; public Visibility Visibility { get { return visibility; } set { visibility = value; RaisePropertyChanged(); } } private string content; public string Content { get { return content; } set { content = value; RaisePropertyChanged(); } } private void Cancel(object p) { if (DialogHost.IsDialogOpen(DialogHostName)) DialogHost.Close(DialogHostName, new CommonDialogResult() { Button = CommonDialogButton.Cancel, Data = null }); } private void Sure(object p) { if (DialogHost.IsDialogOpen(DialogHostName)) { DialogHost.Close(DialogHostName, new CommonDialogResult() { Button = CommonDialogButton.Ok, Data = null }); } } private string DialogHostName { get; set; } = "Root"; public DelegateCommand SureCommand { get; set; } public DelegateCommand CancelCommand { get; set; } public void InitParams(CommonDialogParams p) { DialogHostName = p.DialogHost; Title = p.DialogTitle; Content = p.DialogTipText; Visibility = p.IsQuestion ? Visibility.Visible : Visibility.Hidden; } }
以下两个静态方法,分别调用信息输入框和信息提示/确认框。
internal class CommonDialogShow { public static async Task<object> ShowInputDialog(string host, string title, string tipText, string defaulvalue) { CommonDialogParams ps = new CommonDialogParams() { DialogHost = host, DialogTitle = title, DialogTipText = tipText, DefaultText = defaulvalue }; return await DialogHost.Show(new InputView(ps), host); } public static async Task<object> ShowMessageDialog(string host, string title, string tipText, bool isQuestion) { CommonDialogParams ps = new CommonDialogParams() { DialogHost = host, DialogTitle = title, DialogTipText = tipText, IsQuestion=isQuestion }; return await DialogHost.Show(new MessageView(ps), host); } public static async Task<object> ShowCurcularProgress(string host, Action action) { DialogHost.Show(new CurcularProgressView(), host); try { await Task.Run(() => { action(); }); return new CommonDialogResult() { Button = CommonDialogButton.Ok }; } finally { DialogHost.Close(host); } } }
新建类MainWindowViewModel作为MainWindow的ViewModel,具体代码实现如下:
internal class MainWindowViewModel : ViewModelBase { private string textValue="Hello, you can change this text !"; public string TextValue { get { return textValue; } set { textValue = value; RaisePropertyChanged(); } } public DelegateCommand UpdateCommand { get { return new DelegateCommand(async (src) => { CommonDialogResult result = await CommonDialogShow.ShowInputDialog("Root", "edit", "please edit the text", src.ToString()) as CommonDialogResult; if (result.Button == CommonDialogButton.Ok) { await CommonDialogShow.ShowCurcularProgress("Root", () => { System.Threading.Thread.Sleep(2000); TextValue = result.Data.ToString(); }); } }); } } public DelegateCommand DeleteCommand { get { return new DelegateCommand(async (src) => { CommonDialogResult result = await CommonDialogShow.ShowMessageDialog("Root", "caution", "do you want to delete the text?", true) as CommonDialogResult; if (result.Button == CommonDialogButton.Ok) { await CommonDialogShow.ShowCurcularProgress("Root", () => { System.Threading.Thread.Sleep(2000); TextValue = ""; }); await CommonDialogShow.ShowMessageDialog("Root", "success", "the text has been deleted!", false); } }); } } }
最后,将本demo的完整源码分享在csdn上,欢迎下载共同学习和交流。
源码下载
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。