在WPF中使用命令模型,对于实现ICommandSource的元素来讲,比较方便,对于未实现ICommandSouce的元素来讲可以利用Blend中提供的行为来解决。通常情况下,命令对象可以传递命令参数(CommandParameter),如果将鼠标事件用命令来解决,则往往需要关注鼠标的位置,如果在事件处理方法中可以通过MouseEventArgs对象来获取。那如果在命令中获取鼠标位置呢,可能有多种解决方法,本文主要介绍一种利用Mouse.GetPosition(IInputElement)方法来获取鼠标相对于WPF元素的位置,以及利用Win32API 函数GetCursorPos()来获取屏幕鼠标位置的方法。
Xaml代码如下:
<Window.Resources>
<vm:MyViewModel x:Key="myViewModel"></vm:MyViewModel>
</Window.Resources>
<StackPanel DataContext="{StaticResource myViewModel}">
<Label Name="label" Content="my"/>
<Canvas Name="canvas" Height="400" MouseMove="btn_MouseMove" Background="AliceBlue">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding ShowMessageBoxCommand}" CommandParameter="{Binding ElementName=canvas}" />//将canvas作为参数传入,在viewmodel中通过Mouse.GetPosition(canvas)来获取鼠标位置
//说明:此处如果换成Prism库中的InvokeCommandAction,则可以直接将EventArgs对象属性或对象本身传递给Command, 例如在集合控件ListBox中写成<prism:InvokeCommandAction Command={Binding SelectedCommand}" TriggerParameterPath="AddedItems"/>,此处的AddedItems就是SelectionChangedEventArgs对象的属性,这样就可以把EventArgs对象属性传递给了命令,在viewModel中处理命令对象就可以很方便的获取到事件对象的属性。如果直接传递EventArs对象,则省略TriggerParameterPath属性或者将该属性写成TriggerParameterPath=""即可。(个人理解:做MVVM开发时,尽量不要将界面控件如Canvas或WPF事件对象EventArgs直接传递给ViewModel,这会造成ViewModel对象对界面控件类型的依赖,尽可能仅传递所用到的事件对象的参数即可)
补充:如果采用Prism库中的prism:InvokeCommandAction,那么就可以传递TriggerParameterPath,可以把事件对象本身或事件对象的属性作为CommandParameter传递给ViewModel中的DelegateCommand对象,就不用把界面元素传给ViewModel了。参考:https://blog.csdn.net/jiuzaizuotian2014/article/details/104845775
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<i:InvokeCommandAction Command="{Binding ShowScreenMousePositionCommand}" CommandParameter="{Binding ElementName=label}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Canvas>
</StackPanel>
在ViewModel中的代码如下:
public class MyViewModel:BindableBase
{
private string _myProperty = "";
public string MyProperty { get { return _myProperty; } set { SetProperty(ref _myProperty, value);
RaisePropertyChanged();
} }
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool GetCursorPos(out POINT pt);
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
}
public ICommand ShowMessageBoxCommand
{
get
{
return new DelegateCommand<Canvas>((c) => { //DelegateCommand<T>来自于Prism框架
Point p = Mouse.GetPosition(c);
MessageBox.Show($"x={p.X},y={p.Y}"); //显示鼠标在Canvas上的位置
});
}
}
public ICommand ShowScreenMousePositionCommand
{
get
{
return new DelegateCommand<Label>((c) => {
POINT p = new POINT(); //利用自定义的POINT结构体,参数类型为整数。
//注:System.Windows.Point结构体的参数是浮点
GetCursorPos(out p);//利用win32API获取鼠标在显示屏上的位置
c.Content = string.Format("{0},{1}", p.X, p.Y);
});
}
}
}
}