一、System.Windows.Interactivity 的使用
對於 Button 等控件,在 MVVM 中我們能通過 Command 綁定解決 Click 事件,具體如下:
<Button Margin="10" Height="50" Content="Clear" Command="{Binding Path=Clear}"></Button>
此時,當我們單擊 Clear 按鈕時,會執行 “Clear“ 命令。若我們需要傳遞參數,則使用 CommandParameter,如下所示傳遞:
<Button Margin="10" Height="50" Content="Clear" Command="{Binding Path=Clear}" CommandParameter="{Binding Path=Student}"></Button>
那當我們使用 Button 的 其他事件,例如MouseMove 事件呢?甚至 TextBox 控件沒有 Command 屬性, 該如何使用 Command 呢?
這就需要我們通過 Nuget 添加 “System.Windows.Interactivity” 包后,引入如下命名控件:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
例如,我們實現一個 TextBox的 TextChanged事件,當文本內容發生變化,彈出踢提示信息:
<TextBox Height="50" VerticalContentAlignment="Center" Margin="10" BorderBrush="Black" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding DisplayMessage}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
二、帶事件參數(EventArgs)的事件綁定
上面介紹的事件綁定並不足以應對所有的情況,因為很多情況下我們還需要從事件的EventArgs中獲取數據,例如從MouseMove事件參數中獲取鼠標位置和按鍵狀態等。但InvokeCommandAction在未對CommandParameter綁定的情況下給Execute方法傳遞的參數為null。因此我們需要自己寫一個類來處理事件到命令的綁定。自定義 EventCommand 如下所示:
class EventCommand : TriggerAction<DependencyObject>
{
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
// Using a DependencyProperty as the backing store for Command. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(EventCommand), new PropertyMetadata(null));
public object CommandParameter
{
get { return (object)GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
// Using a DependencyProperty as the backing store for CommandParameter. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(EventCommand), new PropertyMetadata(null));
protected override void Invoke(object parameter)
{
if (CommandParameter != null)
{
parameter = CommandParameter;
}
Command?.Execute(parameter);
}
}
例如,我們要實現對一個 TextBox 鼠標位置信息的獲取,具體綁定如下:
<TextBox Height="150" Margin="10" Background="LightSteelBlue" Text="獲取鼠標位置" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseMove">
<local:EventCommand Command="{Binding GetPositionCommand}"></local:EventCommand>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
如此,ViewModel 的綁定命令就可以收到事件參數了:
public ICommand GetPositionCommand { get; set; }
private void GetPositionCommandExecute(object obj)
{
var args = obj as MouseEventArgs;
if (args != null)
{
var pos = args.GetPosition(args.Device.Target);
CurrentPosition = new Position()
{
X = pos.X,
Y = pos.Y,
};
}
}
public WindowVM()
{
_position = new Position();
GetPositionCommand=new RelayCommand(GetPositionCommandExecute, null);
}