WPF MVVM 从代码隐藏调用 ViewModel 方法



首先,我对WPF MVVM很陌生,有点困惑。人们说,通常在 MVVM 中,最佳做法是不要隐藏任何代码。 我发现有些方法在代码隐藏中比在视图模型中更容易实现(例如MouseMove),这让我思考以下这两个例子的差异:

1) 使用RelayCommand

视图

<Button Command="{Binding AlertCommand}"></Button>

视图模型

public RelayCommand AlertCommand { get; set; }
public void Alert()
{
MessageBox.Show("message");
}

2) 从代码隐藏调用ViewModel方法:

视图

<Button PreviewMouseLeftButtonUp="OnMouseLeftButtonUp"></Button>

查看代码隐藏

private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var ctx = (MainViewModel) this.DataContext;
ctx.Alert();
}

在这里使用背后的代码是错误的吗?不使用代码隐藏有什么好处?

MVVM 模式是构建 UWP、WPF 和 Xamarin.Forms 应用时的最佳做法。主要优点是,您能够将逻辑与演示文稿分离,并且可能通过多个不同的视图呈现单个视图模型,并且可以切换视图而无需对视图模型进行重大修改。在使用本机UI构建跨平台应用程序时,这是一个很大的优势,例如MvvmCross框架在很大程度上使用了本机UI。

然而,拥有一个空的代码隐藏绝对只是一个理想,这通常并不容易,并不总是需要实现。有时您需要使用代码隐藏进行纯粹与视图相关的操作,例如更改不同窗口大小的布局、控制动画等。对于此类操作,代码隐藏比尝试以某种方式将其强制到 VM 中要合适得多。

比较这两种方法时,最好使用基于RelayCommand的方法而不是直接方法调用,因为它与方法本身的直接联系较少。如果需要,可以在运行时将 VM 中的RelayCommand实例切换为不同的实现(调用不同的方法),并且由于绑定了按钮,现在可以执行不同的操作。这可用于类似编辑器的应用程序,其中某些工具可能根据应用程序所在的当前上下文具有不同的功能。

此外,对于不提供Command的控件,您可以EventTriggerInvokeCommandAction(两者都在 Expression Blend SDK 中定义)一起使用,这将允许您将事件"转换"为命令调用,即使您定义了EventArgs转换。

两者都是有效的方法。如果可能的话,第一个是可取的。我通常在没有命令绑定可用的事件上使用第二种方法。"MVVM 中绝对没有代码隐藏"的概念是值得商榷的。任何直接属于视图(并且不是业务逻辑)且不可在 VM 中重用的代码都可以放在代码隐藏中,例如在第二个示例中连接事件。