对话框的MVVM实现

来源:互联网 发布:记账小软件 编辑:程序博客网 时间:2024/05/20 19:46

如果你决定让你的应用程序应用MVVM模式的话,那么对话框的MVVM实现就会成为你要考虑的众多问题中的一个,因为基本上每一个应用程序都会有对话框,你的应用程序可能也不例外。

在用MVVM实现对话框的时候,我们主要会遇到两大问题:

1. ViewModel怎么关闭对话框,或者说怎么处理对话框的一些事件。

2. ViewModel中弹出对话框应该怎么处理 -- 弹出对话框会使UnitTest失败。

 

第一个问题: ViewModel怎么关闭对话框

假如你实现的对话框中有一个“确定”按钮,并且在ViewModel中有一个对应的命令绑定到这个按钮中,在这个按钮的命令处理函数中你需要关闭这个对话框。由于ViewModel并不知道对话框的存在,所以在ViewModel中是做不到直接关闭对话框的操作的。既然不能直接关闭,那就只能使用间接的方式来关闭对话框。下面介绍其中的一种方式:

定义一个接口:

public interface IDialogRequest

{

      event EventHandler RequestClose;

}

让ViewModel实现这个接口,当需要关闭对话框的时候就触发这个事件。

 

那么谁来注册这个事件,以及在哪里注册?

你可能会直接在对话框的类中写这样的代码来注册RequestClose事件:

IDialogRequest dialogRequest = DataContext as IDialogRequest;

if(dialogRequest != null)

{

    dialogRequest.RequestClose += ....;

}

这种方法很直接,但是并不是很理想,因为这样就意味着我们需要写Code-Behind代码了。

既然这样不是很好,那么该怎么办呢?我们可以使用Attached Property来解决这个问题,实现一个这样的类:

public class DialogRequstUtil

{

    public static readonly DependencyProperty EnableDialogRequestProperty = Dependency.RegisterAttached(...);

    ...

    //你可以在这个类是注册DialogRequest的事件

}

 

然后你就可以在XAML里面这样写:

<Window utils:DialogRequestUtil.EnableDialogRequest = "true" .../>

或者在代码中这样实现:

DialogRequestUtil.SetEnableDialogRequest(window, true);

 

这是目前使用的比较简单的解决方法。

 

第二个问题: ViewModel中弹出对话框应该怎么处理

经过Google,Bing,Baidu之后,找到了一种解决这个问题稍微比较好的方法--使用回调的方法,也就是我们在ViewModel中并不会直接去打开一个对话框,比如OpenFileDialog。而是调用一个回调函数,让这个回调函数去处理,这样就可以避免在UnitTest中弹出对话框,因为我们可以在UnitTest中实现另外一个不弹出对话框的回调函数。具体可以这么做:

public class TestViewModel

{

    pubilc TestViewModel(Callback openFileDialogCallback)

    {...}

    

     private void OpenFileDialog()

     {

          openFileDialogCallback(...);

     }

}

 

当我们在创建ViewModel的时候直接把回调函数传进来,这样做的目的就是可以让外部来控制是否要显示一个对话框。如果项目遇到这样的问题,不妨试一下这种方法。

 

优化代码

 下面是打开一个对话框的场景,这样的代码也是很自然的:

MyDialog myDialog = new Dialog();

myDialow.Owner = MainWindow;

...

if(myDialog.ShowDialog() == true)

{

...

}

 

但是使用了MVVM之后,代码会变得复杂,也很不简洁,可能会变成这样:

MyDialogViewModel myDialogViewModel = new myDialogViewModel();

...

 

MyDialog myDialog = new Dialog()

myDialog.DataContext = myDialogViewModel;

myDialog.Owner = MainWindow;

if(myDialog.ShowDialog() == true)

{

...

}

 

你会发现我们不单单要初始化对话框,同时也需要初始化ViewModel。我们并不需要为所有的对话框都定义一个类,对话框里面的内容可以让ViewModel的数据模板来定义,我们可以实现代码:

MyDialogViewModel myDialogViewModel = new MyDialogViewModel();

...

if(DialogService.ShowDialog(myDialogViewMode, layoutResourceDictionary, MainWindow) == true)

{

...

}

这样的代码显得更加简洁自然,而且也不用去专门定义一个对话框类。所有对话框的显示和属性设置都由辅助类DialogService来实现。

 

 

原创粉丝点击