【问题标题】:View knowledge about ViewModel查看有关ViewModel的知识
【发布时间】:2015-09-04 06:32:40
【问题描述】:

我需要将 View(WPF 窗口)中的方法连接到 ViewModel 中的事件。鉴于具体的 VM 类型并连接其事件,是否违反了 MVVM 模式到 DirectCast Object DataContext?如果是,有没有更好的方法?

【问题讨论】:

  • 您希望连接哪种类型的方法?它们是事件吗?
  • 1) 在 VM 上公开命令 2) 在视图上添加命令属性 3) 绑定它们并 4) 在需要时从视图中执行它们。

标签: wpf mvvm


【解决方案1】:

首先看看视图中的方法是做什么的。如果他们操纵视图,请考虑将属性添加到您在视图模型中的事件中更改的视图模型并将视图绑定到。这样,通过将视图绑定到属性,您就无需在视图中编写代码了。

如果方法包含其他逻辑,请考虑将该逻辑移至视图模型。

在其他情况下,将 DataContext 转换为视图模型或接口可能是一个有效的选项,并且不违反 MVVM 模式。

向视图添加代码时,请考虑进行测试。自动化/单元测试视图比测试视图模型更难。

【讨论】:

  • 事件在我的 VM 中公开,因为:VM 需要在 SaveFileDialog 中选择文件名(由 View 显示)并且 VM 需要使用 MessageBox 确认某些操作(也由 View 显示)。 VM 中的常规操作(例如保存更改或读取数据)通过 ICommand 公开。
  • 您可以创建一个显示对话框并返回结果的视图服务(文件名,ok/cancel)并在视图模型中调用该服务。
  • 创建一些 ViewService/DialogService 是不必要的,并且不会比我的解决方案带来任何优势。
  • 确实如此。视图服务可以很容易地被模拟存根,因此您可以测试视图模型而无需依赖单击对话框按钮
  • 我可以附加模拟用户点击该事件的方法,它比你的模拟要容易三倍。
【解决方案2】:

这并不违反 MVVM 模式,但当然越抽象越好(不是因为 MVVM,而是作为一般的良好实践)。

如果您在 XAML 上设置 DataContext,则可以通过使用 Interactivity EventTriggerCallMethodAction 来保持它的抽象...也许。但是如果你在代码隐藏中设置它(通过注入或其他方式),你要么将 DataContext 转换为已知类型,要么使用反射(我不会>_>)。

一般来说,为您的 ViewModel 创建一个接口,这样您就可以保持适当的抽象级别,并且只公开视图需要知道的内容而不是其整个实现,这对于大多数场景来说已经足够了。

public interface IMyViewModel
{
    event EventHandler MyEvent;
}

public class MyViewModel : IMyViewModel
{
    public event EventHandler MyEvent;

    // More viewmodel related stuff

    protected virtual void OnMyEvent(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

public class MyWindow : Window
{
    public MyWindow(IMyViewModel viewModel)
    {
        this.DataContext = viewModel;
        InitializeComponent();
        (this.DataContext as IViewModel).MyEvent += MyEventHandler;
    }

    private void MyEventHandler(object sender, EventArgs e)
    {
        // Do view related stuff
    }

}

【讨论】:

  • 我不能使用接口进行抽象,因为我的虚拟机包含很多非常不同的成员,所以我不能为所有东西创建通用的东西。
猜你喜欢
  • 2012-08-21
  • 1970-01-01
  • 2018-10-02
  • 1970-01-01
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
  • 2019-07-14
  • 1970-01-01
相关资源
最近更新 更多