WPF OpenFileDialog与MVVM模式?

Jud*_*ngo 95 wpf openfiledialog mvvm

我刚开始学习WPF的MVVM模式.我碰壁了:当你需要展示一个OpenFileDialog时你会怎么做

这是我尝试使用它的示例UI:

替代文字

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

我怎么能用MVVM做到这一点?

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

And*_*mes 92

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

这是一个用于执行OpenFileDialog和OpenFile等基本IO操作的极其简单的接口示例.我在这里展示它们所以你不认为我建议你用一种方法创建一个接口来解决这个问题.

public interface IOService
{
     string OpenFileDialog(string defaultPath);

     //Other similar untestable IO operations
     Stream OpenFile(string path);
}
Run Code Online (Sandbox Code Playgroud)

在您的应用程序中,您将提供此服务的默认实现.这是你如何消费它.

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;
          }
     }
}
Run Code Online (Sandbox Code Playgroud)

所以这很简单.现在是最后一部分:可测试性.这个应该是显而易见的,但我会告诉你如何为此做一个简单的测试.我使用Moq进行存根,但你可以使用你想要的任何东西.

[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);
}
Run Code Online (Sandbox Code Playgroud)

这可能对你有用.

CodePlex上有一个名为"SystemWrapper"的库(http://systemwrapper.codeplex.com),它可以帮助您避免执行大量此类操作.看起来它还没有支持FileDialog,所以你肯定必须为那个编写一个接口.

希望这可以帮助.

编辑:

我似乎记得你喜欢TypeMock Isolator用于伪造框架.这是使用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);
}
Run Code Online (Sandbox Code Playgroud)

希望这也有帮助.

  • 为什么要从VM打开对话框?与用户交互以获取文件名是视图的责任. (8认同)
  • 如何在View端实现IOService? (3认同)

jbe*_*jbe 5

WPF应用程序框架(WAF)提供了开放式和SaveFileDialog的实现。

Writer示例应用程序显示了如何使用它们以及如何对代码进行单元测试。