前言
本文通过一个简单的demo示例,介绍了MaterialDesign在wpf应用程序中的使用,实现wpf的mvvm,并封装了MaterialDesign酷炫的弹窗对话框,在此做一些总结,并在文章的最后分享完整源码。
demo效果如下:
搭建MaterialDesign开发环境
添加引用
在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的简单封装
在不使用第三方mvvm框架的情况下,我对INotifyPropertyChanged(绑定UI显示)和ICommand(绑定命令)进行了简单封装。如下:
ViewModelBase
internalclassViewModelBase:INotifyPropertyChanged{publiceventPropertyChangedEventHandler? PropertyChanged;protectedvoidRaisePropertyChanged([CallerMemberName]string property=null){
PropertyChanged?.Invoke(this,newPropertyChangedEventArgs(property));}}
DelegateCommand
internalclassDelegateCommand:ICommand{publicDelegateCommand(Action<object> action){
_action = action;}privateAction<object> _action;publiceventEventHandler? CanExecuteChanged;publicboolCanExecute(object? parameter){returntrue;}publicvoidExecute(object? parameter){
_action?.Invoke(parameter);}}
对话框设计
一般在cs程序中最常用的对话框就是信息提示框、确认对话框、信息输入框、等待进度提示框等。这里我进行了封装,信息输入框(InputView)、信息提示/确认对话框(MessageView)、转圈等待提示框(CurcularProgressView),其中MessageView既可以做信息提示框,也可以做确认询问框。
InputView
新建一个用户控件,取名“InputView”,以此作为信息输入框。界面设计如下:
其中,输入框的标题、提示语、默认值,都是可以通过传入参数配置的。
MessageView
新建一个用户控件,取名“MessageView”,以此作为信息提示/确认对话框。界面设计如下:
其中,对话框的标题、提示语、Cancel按钮是否可见(是否询问对话框),都是可以通过传入参数配置的。
CurcularProgressView
对话框的参数传递及数据回传
为对话框的参数传递及数据回传,设计专门的类
internalenumCommonDialogButton{
Cancel=0,//取消
Ok=1//确认}/// <summary>/// 对话框返回的结果/// </summary>internalclassCommonDialogResult{/// <summary>/// 点击了哪个按钮/// </summary>publicCommonDialogButton Button {get;set;}/// <summary>/// 回传的数据/// </summary>publicobject Data {get;set;}}/// <summary>/// 对话框的参数/// </summary>publicclassCommonDialogParams{/// <summary>/// 对话框悬停的Host名称/// </summary>publicstring DialogHost {get;set;}="Root";/// <summary>/// 对话框的标题/// </summary>publicstring DialogTitle {get;set;}/// <summary>/// 对话框的提示语/// </summary>publicstring DialogTipText {get;set;}/// <summary>/// 如果是输入框,则可设置默认值/// </summary>publicstring DefaultText {get;set;}/// <summary>/// 是否是询问对话框/// </summary>publicbool IsQuestion {get;set;}}
ViewModel类(主要的功能实现类)
InputViewModel
internalclassInputViewModel:ViewModelBase{publicInputViewModel(){
SureCommand =newDelegateCommand(Sure);
CancelCommand =newDelegateCommand(Cancel);}privatestring title;publicstring Title
{get{return title;}set{ title =value;RaisePropertyChanged();}}privatestring tipText;publicstring TipText
{get{return tipText;}set{ tipText =value;RaisePropertyChanged();}}privatestring inputString;publicstring InputString
{get{return inputString;}set{ inputString =value;RaisePropertyChanged();}}privatevoidCancel(object p){if(DialogHost.IsDialogOpen(DialogHostName))
DialogHost.Close(DialogHostName,newCommonDialogResult(){Button=CommonDialogButton.Cancel,Data=null});}privatevoidSure(object p){if(string.IsNullOrEmpty(InputString))return;if(DialogHost.IsDialogOpen(DialogHostName)){
DialogHost.Close(DialogHostName,newCommonDialogResult(){ Button = CommonDialogButton.Ok, Data = inputString });}}privatestring DialogHostName {get;set;}="Root";publicDelegateCommand SureCommand {get;set;}publicDelegateCommand CancelCommand {get;set;}publicvoidInitParams(CommonDialogParams p){
DialogHostName = p.DialogHost;
Title = p.DialogTitle;
TipText = p.DialogTipText;
InputString = p.DefaultText;}}
MessageViewModel
internalclassMessageViewModel:ViewModelBase{publicMessageViewModel(){
SureCommand =newDelegateCommand(Sure);
CancelCommand =newDelegateCommand(Cancel);}privatestring title;publicstring Title
{get{return title;}set{ title =value;RaisePropertyChanged();}}privateVisibility visibility = Visibility.Visible;publicVisibility Visibility
{get{return visibility;}set{ visibility =value;RaisePropertyChanged();}}privatestring content;publicstring Content
{get{return content;}set{ content =value;RaisePropertyChanged();}}privatevoidCancel(object p){if(DialogHost.IsDialogOpen(DialogHostName))
DialogHost.Close(DialogHostName,newCommonDialogResult(){ Button = CommonDialogButton.Cancel, Data =null});}privatevoidSure(object p){if(DialogHost.IsDialogOpen(DialogHostName)){
DialogHost.Close(DialogHostName,newCommonDialogResult(){ Button = CommonDialogButton.Ok, Data =null});}}privatestring DialogHostName {get;set;}="Root";publicDelegateCommand SureCommand {get;set;}publicDelegateCommand CancelCommand {get;set;}publicvoidInitParams(CommonDialogParams p){
DialogHostName = p.DialogHost;
Title = p.DialogTitle;
Content = p.DialogTipText;
Visibility = p.IsQuestion ? Visibility.Visible : Visibility.Hidden;}}
调用对话框的静态方法
以下两个静态方法,分别调用信息输入框和信息提示/确认框。
internalclassCommonDialogShow{publicstaticasyncTask<object>ShowInputDialog(string host,string title,string tipText,string defaulvalue){CommonDialogParams ps =newCommonDialogParams(){ DialogHost = host, DialogTitle = title, DialogTipText = tipText, DefaultText = defaulvalue };returnawait DialogHost.Show(newInputView(ps), host);}publicstaticasyncTask<object>ShowMessageDialog(string host,string title,string tipText,bool isQuestion){CommonDialogParams ps =newCommonDialogParams(){ DialogHost = host, DialogTitle = title, DialogTipText = tipText, IsQuestion=isQuestion };returnawait DialogHost.Show(newMessageView(ps), host);}publicstaticasyncTask<object>ShowCurcularProgress(string host,Action action){
DialogHost.Show(newCurcularProgressView(), host);try{await Task.Run(()=>{action();});returnnewCommonDialogResult(){ Button = CommonDialogButton.Ok };}finally{
DialogHost.Close(host);}}}
MainWindow调用对话框
新建类MainWindowViewModel作为MainWindow的ViewModel,具体代码实现如下:
internalclassMainWindowViewModel:ViewModelBase{privatestring textValue="Hello, you can change this text !";publicstring TextValue
{get{return textValue;}set{ textValue =value;RaisePropertyChanged();}}publicDelegateCommand UpdateCommand
{get{returnnewDelegateCommand(async(src)=>{CommonDialogResult result =await CommonDialogShow.ShowInputDialog("Root","edit","please edit the text", src.ToString())asCommonDialogResult;if(result.Button == CommonDialogButton.Ok){await CommonDialogShow.ShowCurcularProgress("Root",()=>{
System.Threading.Thread.Sleep(2000);
TextValue = result.Data.ToString();});}});}}publicDelegateCommand DeleteCommand
{get{returnnewDelegateCommand(async(src)=>{CommonDialogResult result =await CommonDialogShow.ShowMessageDialog("Root","caution","do you want to delete the text?",true)asCommonDialogResult;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上,欢迎下载共同学习和交流。
源码下载
版权归原作者 hyq106 所有, 如有侵权,请联系我们删除。