使用 MVVM 模式的 WPF OpenFileDialog? [英] WPF OpenFileDialog with the MVVM pattern?

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

问题描述

我刚刚开始学习 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).

下面是一个极其简单的接口示例,用于执行诸如 OpenFileDialogOpenFile 之类的基本 IO 操作.我在这里展示了它们,所以您不会认为我建议您使用一种方法创建一个界面来解决这个问题.

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:WhereMyFileUsuallyIs.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)这可能会使您不必做很多这样的事情.很多.看起来 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 Isolator 作为你的伪造框架.下面是使用 Isolator 的相同测试:

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);
}

希望这也能有所帮助.

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

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