我刚刚开始学习WPF的MVVM模式。我碰壁了:当你需要显示OpenFileDialog
时,你该怎么做?
下面是我尝试使用它的一个示例UI:
单击浏览按钮时,应该会显示一个OpenFileDialog
。当用户从OpenFileDialog
中选择一个文件时,文件路径应显示在文本框中。
如何使用MVVM执行此操作?
MVVM :如何使用更新并使其可进行单元测试?下面的解决方案不适用于单元测试。
发布于 2009-10-26 11:48:38
我通常做的是为执行此功能的应用程序服务创建一个接口。在我的例子中,我假设你使用的是MVVM Toolkit或类似的东西(这样我就可以得到一个基本的ViewModel和一个RelayCommand
)。
这是一个非常简单的接口示例,用于执行基本的IO操作,如OpenFileDialog
和OpenFile
。我在这里展示了它们,所以你不会认为我是在建议你用一个方法创建一个接口来解决这个问题。
public interface IOService
{
string OpenFileDialog(string defaultPath);
//Other similar untestable IO operations
Stream OpenFile(string path);
}
在您的应用程序中,您将提供此服务的默认实现。以下是您将如何使用它。
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进行存根,当然你可以使用任何你喜欢的东西。
[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
,所以你必须为它写一个接口。
希望这能有所帮助。
编辑
我似乎记得你偏爱TypeMock隔离器作为你的伪装框架。下面是使用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);
}
希望这也是有帮助的。
发布于 2009-10-26 16:39:24
为开放和SaveFileDialog提供了一种实现。
Writer示例应用程序展示了如何使用它们以及如何对代码进行单元测试。
发布于 2009-10-25 09:19:25
首先,我建议您从WPF MVVM toolkit开始。这为您的项目提供了很好的命令选择。自从MVVM模式引入以来,一个非常出名的特性是RelayCommand (当然还有其他版本,但我只是坚持使用最常用的版本)。它是ICommand接口的一个实现,允许您在ViewModel中创建一个新命令。
回到你的问题,这里有一个你的ViewModel可能是什么样子的例子。
public class OpenFileDialogVM : ViewModelBase
{
public static RelayCommand OpenCommand { get; set; }
private string _selectedPath;
public string SelectedPath
{
get { return _selectedPath; }
set
{
_selectedPath = value;
RaisePropertyChanged("SelectedPath");
}
}
private string _defaultPath;
public OpenFileDialogVM()
{
RegisterCommands();
}
public OpenFileDialogVM(string defaultPath)
{
_defaultPath = defaultPath;
RegisterCommands();
}
private void RegisterCommands()
{
OpenCommand = new RelayCommand(ExecuteOpenFileDialog);
}
private void ExecuteOpenFileDialog()
{
var dialog = new OpenFileDialog { InitialDirectory = _defaultPath };
dialog.ShowDialog();
SelectedPath = dialog.FileName;
}
}
ViewModelBase和RelayCommand都来自MVVM Toolkit。下面是XAML可能的样子。
<TextBox Text="{Binding SelectedPath}" />
<Button Command="vm:OpenFileDialogVM.OpenCommand" >Browse</Button>
和你背后的XAML.CS代码。
DataContext = new OpenFileDialogVM();
InitializeComponent();
就是这样。
随着你对这些命令越来越熟悉,你还可以设置条件,比如什么时候禁用Browse按钮,等等。我希望这能为你指明你想要的方向。
https://stackoverflow.com/questions/1619505
复制相似问题