序言
WPF VM中处理V的事件,这是一个老生常谈的问题。
无论什么时候总能在网上搜到一些MVVM的理想主义者,企图用"你程序设计不合理“去逃避这个问题。但是现实是这个问题确实存在,我们有时候也确实需要去解决。
这里我不想依次陈列出各种方案,因为这是9102年的文章,相信读者也都能搜到各种历史资料。
最佳实践就是微软官方的Behavior的方式。这里主要结合历史资料讲一下使用方法(老瓶装新酒…)。
正文
首先是引用库,老文章可能会让使用Blend SDK,但是微软已开源了XamlBehaviorsWpf项目,并提供了官方NuGet包。
这里直接搜索 Microsoft.Xaml.Behaviors 选择对应的包即可,这里我们使用 Microsoft.Xaml.Behaviors.Wpf
在ViewModel中处理事件我们可以通过 CallMethodAction 和 InvokeCommandAction 两种方式来解决
View的xaml里面
<Window x:Class="TestBehavior.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
Title="MainWindow"
Width="100"
Height="100"
mc:Ignorable="d">
<Grid>
<Rectangle x:Name="Element"
Width="50"
Height="50"
Fill="Red">
<b:Interaction.Triggers>
<b:EventTrigger EventName="MouseLeftButtonDown">
<b:CallMethodAction TargetObject="{Binding}" MethodName="NoParameMethod" />
</b:EventTrigger>
<b:EventTrigger EventName="MouseLeftButtonDown">
<b:CallMethodAction TargetObject="{Binding}" MethodName="OriginParameMethod" />
</b:EventTrigger>
<b:EventTrigger EventName="MouseLeftButtonDown">
<b:InvokeCommandAction Command="{Binding NoParameCommand}" />
</b:EventTrigger>
<b:EventTrigger EventName="MouseLeftButtonDown">
<b:InvokeCommandAction Command="{Binding OneParameCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</Rectangle>
</Grid>
</Window>
ViewModel的cs文件里面
/// <summary>
/// 由事件触发无参数的方法
/// </summary>
public void NoParameMethod()
{
Trace.TraceInformation(nameof(NoParameMethod));
}
/// <summary>
/// 由事件触发和事件一致参数的方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void OriginParameMethod(object sender, MouseButtonEventArgs e)
{
Trace.TraceInformation($"{nameof(OriginParameMethod)} {sender.GetType()} {e.GetPosition(sender as IInputElement)} ");
}
/// <summary>
/// 由事件触发无参数的命令
/// </summary>
public ICommand NoParameCommand
{
get
{
return new ActionCommand(() =>
{
Trace.TraceInformation(nameof(NoParameCommand));
});
}
}
/// <summary>
/// 由事件触发有一个参数的命令
/// </summary>
public ICommand OneParameCommand
{
get
{
return new ActionCommand(_ =>
{
Trace.TraceInformation($"{nameof(OneParameCommand)} {_.GetType()}");
});
}
}
调试输出
TestBehavior.exe Information: 0 : NoParameMethod
TestBehavior.exe Information: 0 : OriginParameMethod System.Windows.Shapes.Rectangle 30,33.5
TestBehavior.exe Information: 0 : NoParameCommand
TestBehavior.exe Information: 0 : OneParameCommand System.Windows.Controls.Grid
拓展
某些应用场景,可能需要多个事件联合处理,比如复杂的画图板功能,地图软件的标注功能等,需要对鼠标点击并拖动,鼠标按住左键并拖动等组合操作实现不同的功能
可以继承并自定义Behavior,在Behavior中能和获取View,并注册各种事件,实现多个事件的联合处理。
如果说我看得比别人更远些,那是因为我站在巨人的肩膀上。 --牛顿