获取查找视图模型以触发模态对话框

时间:2011-07-14 16:35:43

标签: c# wpf mvvm binding

什么是让我的viewmodel触发自定义查找控件以抛出一个基本上代表该查找视图模型的模式对话框的正确方法?自定义查找控件的数据上下文是父记录视图模型的数据上下文。查找控件还有另一个DependencyProperty,它绑定到父记录视图模型上的lookupviewmodel属性,这表示子查找视图模型。

方法1)我在lookupviewmodel上使用一个自定义控件知道要监听的事件。

方法2)我尝试在lookupviewmodel的属性的setter中抛出一个验证异常,查找控件的文本属性也绑定了。然后我将ErrorEvent挂钩到自定义查找控件中。但似乎如果用户在此事件中“校正”对话框内的值,则原始值会保持不变。更糟糕的是,即使在我调用Validation.ClearInvalid之后,另一个ErrorEvent仍会触发,以某种方式将错误添加回来。所以一切都在这里工作,因为所有的视图模型都有正确的数据,只是看起来文本框似乎忽略了当在ErrorEvent中时绑定的文本属性在底层数据源上发生了变化。因此,在处理该错误时,我似乎无法纠正错误?

方法2中的另一个子问题是Validation.ClearInvalid不会删除红色错误边框。我不得不手动清除ErrorTemplate。是吗?

我想找到一种方法在控件中使用自然错误处理来使其抛出模态对话框。

2 个答案:

答案 0 :(得分:1)

这不是您使用事件的原因。存在促进解耦的事件:引发事件的对象不应该知道或关心听取它的对象在做什么。您期望事件能够从属性的setter中更改属性的值 - 或者更糟糕的是,您的事件处理程序正在调用正在处理它的事件的属性设置器,这意味着您必须执行某些操作非常讨厌避免堆栈溢出。

您的描述不是很清楚(您正在描述您遇到的问题以及您同时尝试的非工作解决方案,这很令人困惑),但这听起来像是您的问题试图做的更像是:

if (IsValid(value))
{
   _Property = value;
}
else
{
   _Property = GetValueFromDialog();
}

问题在于您不希望视图模型中的代码抛出对话框,因为这会创建无法在WPF应用程序之外进行测试的视图模型。

这种情况下的答案是使用依赖注入。创建一个名为IDialogService的接口:

interface IDialogService
{
   object GetValueFromDialog();
}

现在将此属性添加到视图模型中:

public IDialogService DialogService { get; set; }

以上代码变为:

if (IsValid(value))
{
   _Property = value;
}
else
{
   _Property = DialogService.GetValueFromDialog();
}

创建一个在WPF应用程序中使用的对话框服务,该服务实际上会抛出对话框并获取结果。在应用程序中实例化视图模型时,请执行以下操作:

MyViewModel vm = new MyViewModel { DialogService = new WpfDialogService(); }

因此,在您的应用程序中,属性设置器将显示对话框并获得与您期望的完全相同的结果。

对于单元测试,创建一个如下所示的模拟对话框:

public class MockDialogService : IDialogService
{
   private object Result;

   public MockDialogService(object result)
   {
      Result = result;
   }

   public object GetValueFromDialog() { return Result; }
}

然后您可以编写如下测试:

MyViewModel vm = new MyViewModel { DialogService = MockDialogService(ExpectedResult) };
vm.Property = InvalidValue;
Assert.AreEqual(ExpectedResult, vm.Property);

上述内容实际上是解决方案的草图而不是解决方案 - 根据应用程序使用对话框的方式,您可能需要比此处概述的功能更多的功能。如果你看一下MVVM框架,你会发现它们中的很多都实现了这种或那种对话服务。

答案 1 :(得分:0)

您可以使用像MVVMLight或Prism这样的框架,它允许您以完全分离的方式在不同实体之间传递有效负载。与Prism相比,MVVMLight非常轻巧。它有一个Messanger的概念,它充当系统范围的事件总线。同样,你在Prism中有EventAggregator。