我想在 ViewModel 中使用 SaveFileDialog ,但由于从 ViewModel 绑定到View不正确,我搜索了方法要做到这一点。但我发现一些答案没有完全区分查看形式 ViewModel ,就像这样:
public interface IOService
{
void IMessageBox(string Message);
string ISaveFileDialog(string DefaultPath);
}
public class IDialog : IOService
{
public void IMessageBox(string Message)
{
System.Windows.MessageBox.Show(Message);
}
public string ISaveFileDialog(string DefaultPath)
{
System.Windows.Forms.SaveFileDialog dg = new SaveFileDialog
{
InitialDirectory = DefaultPath,
Filter = "PDF files (*.pdf) | *.pdf"
};
dg.ShowDialog();
if (dg.FileName == null)
dg.FileName = string.Empty;
return dg.FileName;
}
}
他们说,这是服务,使用它会将查看与 ViewModel 分开。但是我们在 ViewModel 中设置了实例:
IDialog iDialog = new IDialog();
所以我想知道,这种方法与直接从 ViewModel 调用 MessageBox 或 SaveFileDialog 之间的差异是什么?
注意: 我也发现了一些可以使用上述服务的内容,但是按照以下方式实现:
public class ExportViewModel : BaseViewModel
{
IOService _IOService;
public ExportViewModel(IOService ioservice)
{
_IOService = ioservice;
.
.
}
}
但我不知道如何将 IOService 作为参数发送到 ExportViewModel (因为我们无法从实例创建实例 界面!)
答案 0 :(得分:3)
您不应直接从VM弹出对话框以实现自动化测试。
如果您调用MessageBox.Show(),您的测试将一直停滞,直到有人关闭对话框。
相反,如果你使用“IMessageBox”进行单元测试,你可以注入一个实际上不显示对话框的实现,而是返回一个特定的值(结果)。
答案 1 :(得分:0)
它是一种抽象,用于将UI问题与视图模型分开,并允许您在单元测试中拦截这些调用。拦截这些调用允许您在测试期间阻止显示对话框(这将阻止测试的执行,而不是好)并验证视图模型是否按预期运行。
将其称为“服务”或调用抽象“IService”没有什么特别之处。这只是对共同模式的暗示
你也可以称它为“IDontTouchUIStuffInMuhViewModel”,但那不是那么优雅。
通过在视图模型中提供接口的实现,可以在运行时轻松解决第二个问题。您的视图模型不应该关心它是如何实现的(polymorphism),因此您可以在运行时传递合法的实现,并在测试期间传递假的实现。
您也可以使用Dependency Injection或Inversion of Control来完成此操作。通过使用Unity等库来实例化视图模型,将根据您配置容器的方式自动提供所有依赖项。