WPF OpenFileDialog与MVVM模式? [英] WPF OpenFileDialog with the MVVM pattern?

查看:164
本文介绍了WPF OpenFileDialog与MVVM模式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始学习WPF的MVVM模式.我碰壁:当需要显示OpenFileDialog时您会怎么做?

I just started learning the MVVM pattern for WPF. I hit a wall: what do you do when you need to show an OpenFileDialog?

这是一个示例UI,我正尝试在以下情况上使用它:

Here's an example UI I'm trying to use it on:

单击浏览按钮时,将显示一个OpenFileDialog.当用户从OpenFileDialog中选择文件时,文件路径应显示在文本框中.

When the browse button is clicked, an OpenFileDialog should be shown. When the user selects a file from the OpenFileDialog, the file path should be displayed in the textbox.

我该如何使用MVVM?

How can I do this with MVVM?

更新:如何使用MVVM进行并使其可以进行单元测试?以下解决方案不适用于单元测试.

Update: How can I do this with MVVM and make it unit test-able? The solution below doesn't work for unit testing.

推荐答案

我通常要做的是为执行此功能的应用程序服务创建接口.在我的示例中,我假设您使用的是MVVM Toolkit之类的东西或类似的东西(因此我可以获得基本的ViewModel和RelayCommand).

What I generally do is create an interface for an application service that performs this function. In my examples I'll assume you are using something like the MVVM Toolkit or similar thing (so I can get a base ViewModel and a RelayCommand).

这里是一个非常简单的界面示例,用于执行基本的IO操作(如OpenFileDialog和OpenFile).我在这里显示了它们两者,所以您不认为我建议您使用一种方法来创建一个接口来解决此问题.

Here's an example of an extremely simple interface for doing basic IO operations like OpenFileDialog and OpenFile. I'm showing them both here so you don't think I'm suggesting you create one interface with one method to get around this problem.

public interface IOService
{
     string OpenFileDialog(string defaultPath);

     //Other similar untestable IO operations
     Stream OpenFile(string path);
}

在您的应用程序中,您将提供此服务的默认实现.这是您的食用方式.

In your application, you would provide a default implementation of this service. Here is how you would consume it.

public MyViewModel : ViewModel
{
     private string _selectedPath;
     public string SelectedPath
     {
          get { return _selectedPath; }
          set { _selectedPath = value; OnPropertyChanged("SelectedPath"); }
     }

     private RelayCommand _openCommand;
     public RelayCommand OpenCommand
     {
          //You know the drill.
          ...
     }

     private IOService _ioService;
     public MyViewModel(IOService ioService)
     {
          _ioService = ioService;
          OpenCommand = new RelayCommand(OpenFile);
     }

     private void OpenFile()
     {
          SelectedPath = _ioService.OpenFileDialog(@"c:\Where\My\File\Usually\Is.txt");
          if(SelectedPath == null)
          {
               SelectedPath = string.Empty;
          }
     }
}

这很简单.现在到最后一部分:可测试性.这应该很明显,但是我将向您展示如何对此进行简单测试.我使用Moq进行存根,但是您当然可以使用任何想要的东西.

So that's pretty simple. Now for the last part: testability. This one should be obvious, but I'll show you how to make a simple test for this. I use Moq for stubbing, but you can use whatever you'd like of course.

[Test]
public void OpenFileCommand_UserSelectsInvalidPath_SelectedPathSetToEmpty()
{
     Mock<IOService> ioServiceStub = new Mock<IOService>();

     //We use null to indicate invalid path in our implementation
     ioServiceStub.Setup(ioServ => ioServ.OpenFileDialog(It.IsAny<string>()))
                  .Returns(null);

     //Setup target and test
     MyViewModel target = new MyViewModel(ioServiceStub.Object);
     target.OpenCommand.Execute();

     Assert.IsEqual(string.Empty, target.SelectedPath);
}

这可能对您有用.

CodePlex上有一个名为"SystemWrapper"的库( http://systemwrapper.codeplex.com )这可能使您不必再做 lot 这样的事情.似乎尚不支持FileDialog,因此您肯定必须为该接口编写一个接口.

There is a library out on CodePlex called "SystemWrapper" (http://systemwrapper.codeplex.com) that might save you from having to do a lot of this kind of thing. It looks like FileDialog is not supported yet, so you'll definitely have to write an interface for that one.

希望这会有所帮助.

修改:

我似乎记得您喜欢使用TypeMock隔离器作为伪造框架.这是使用隔离器的相同测试:

I seem to remember you favoring TypeMock Isolator for your faking framework. Here's the same test using Isolator:

[Test]
[Isolated]
public void OpenFileCommand_UserSelectsInvalidPath_SelectedPathSetToEmpty()
{
    IOService ioServiceStub = Isolate.Fake.Instance<IOService>();

    //Setup stub arrangements
    Isolate.WhenCalled(() => ioServiceStub.OpenFileDialog("blah"))
           .WasCalledWithAnyArguments()
           .WillReturn(null);

     //Setup target and test
     MyViewModel target = new MyViewModel(ioServiceStub);
     target.OpenCommand.Execute();

     Assert.IsEqual(string.Empty, target.SelectedPath);
}

希望这也很有帮助.

这篇关于WPF OpenFileDialog与MVVM模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆