我刚刚开始学习WPF的MVVM模式。我碰壁:当您需要显示OpenFileDialog
时该怎么办?
这是我尝试在其上使用的示例UI:
单击浏览按钮时,应显示一个OpenFileDialog
。当用户从OpenFileDialog
中选择文件时,文件路径应显示在文本框中。
我该如何使用MVVM?
更新:如何使用MVVM做到这一点并使它可进行单元测试?以下解决方案不适用于单元测试。
参考方案
我通常要做的是为执行此功能的应用程序服务创建接口。在我的示例中,我假设您使用的是MVVM Toolkit之类的东西或类似的东西(因此我可以获得基本的ViewModel和RelayCommand
)。
这是一个非常简单的界面示例,用于执行诸如OpenFileDialog
和OpenFile
之类的基本IO操作。我在这里显示了它们两者,所以您不认为我建议您使用一种方法来创建一个接口来解决此问题。
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隔离器作为伪造框架。这是使用隔离器的相同测试:
[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 MVVM中的动态TabControl - c#我几周前开始使用WPF(在C#中),现在我需要一些高级帮助来使用tabcontrol。首先,我正在使用MVVM(模型视图ViewModel)模式来设计我的应用程序,并且我有一个约束,即试图不要在文件(初始化xaml文件)后面的代码中添加代码。现在,我的问题是在MainWindow视图(窗口)中动态创建新的tabItem,当单击按钮(例如“新建选项卡”按钮)时…
获取ListBoxItem的索引-WPF - c#如何获取ListBoxItem的索引?ListBox通过XmlDataProvider绑定到XML节点的集合。 参考方案 我有一个类似的问题,得到了回答here基本上,您将ListBox的AlternationCount设置为非常高的值,并绑定到每个项目上的AlternationIndex<ListBox AlternationCount="…
WPF WebBrowser甚至使用ObjectForScripting在单独的线程上锁定UI - javascript在与WPF Web浏览器控件绑定的ObjectForScripting上调用方法时,网页UI锁定会出现一个奇怪的问题。进一步的研究使我们意识到整个UI(包括WPF应用程序而不是WebBrowser)都已锁定。使用的技术是带有Caliburn.Micro和Autofac的WPF。我在COM可见类上使用方法来推送到Caliburn.Micro提供的事件聚合器。进…
WPF-将窗口大小设置为子用户控件大小 - c#我有一个选项卡控件,该控件动态地填充有包含各种大小的用户控件的选项卡。打开选项卡后,我希望窗口自动调整大小,使其在活动用户控件下有意义。有一种干净的方法可以做到这一点吗?我正在使用标准的mvvm模式。 参考方案 在Window类上使用SizeToContent属性。<Window x:Class="WpfApplication1.MainWi…
在datagrid(wpf)中选择行索引 - c#如何在datagrid中选择行索引? 事件SelectionChanged以下代码不起作用: private DataGridRow dgr = new DataGridRow(); private void dataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { thi…