time-flies的博客

事件绑定意义#
一般事件的处理程序都放在界面后台,通过事件绑定可以把事件处理程序放在ViewModel中,实现界面和逻辑的解耦。

要使用事件绑定需要借助System.Windows.interactivity(安装了Blend就有),如果电脑上找不到,可以通过NuGet安装System.Windows.Interactivity.WPF。

需要引用以下命名空间:

xmlns:i=“http://schemas.microsoft.com/expression/2010/interactivity”
using System.Windows.Interactivity;
无参数的事件绑定#
在Interaction.Triggers里面添加一个或多个EventTrigger并指定关注的的事件名称,在EventTrigger中通过InvokeCommandAction来绑定事件对应的命令,在事件触发后会调用绑定的命令对象的Execute方法执行命令。

命令的实现参考WPF之自定义委托命令,事件触发后是否能够真正执行绑定的命令也受到绑定的命令的CanExecute方法的影响。事件绑定过程如下:

<i:Interaction.Triggers>
<i:EventTrigger EventName=“Loaded”>
<i:InvokeCommandAction Command="{Binding LoadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
带EventArgs参数的事件绑定#
InvokeCommandAction在未对CommandParameter绑定的情况下给Execute方法传递的参数为null,对CommandParameter绑定的情况下给Execute方法传递的参数为绑定值(不是EventArgs参数),Execute方法是由Invoke(object parameter)调用的。

其实,TiggerBase调用InvokeCommandAction的Invoke(object parameter)方法时有传入EventArgs参数,但Invoke调用Execute方法时一直使用的是CommandParameter参数。有一说一,这个程序逻辑有点反人类,这也是网上为什么有这么多重新实现InvokeCommandAction资料的原因。

如果需要从事件的EventArgs中获取数据,正常来说派生InvokeCommandAction然后“重写”Invoke方法即可。但是,InvokeCommandAction是密封类,我们只能参照源码重新实现一个EventCommandAction类,代码如下:

using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace WpfApp
{
public class EventCommandAction : TriggerAction
{
///
/// 事件要绑定的命令
///
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}

    // Using a DependencyProperty as the backing store for MsgName.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), typeof(EventCommandAction), new PropertyMetadata(null));

    /// <summary>
    /// 绑定命令的参数,保持为空就是事件的参数
    /// </summary>
    public object CommandParameter
    {
        get { return (object)GetValue(CommandParateterProperty); }
        set { SetValue(CommandParateterProperty, value); }
    }

    // Using a DependencyProperty as the backing store for CommandParateter.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CommandParateterProperty =
        DependencyProperty.Register("CommandParameter", typeof(object), typeof(EventCommandAction), new PropertyMetadata(null));

    //执行事件
    protected override void Invoke(object parameter)
    {
        if (CommandParameter != null)
            parameter = CommandParameter;
        var cmd = Command;
        if (cmd != null&&cmd.CanExecute(parameter))
            cmd.Execute(parameter);
    }
}

}
使用事件绑定#
创建一个MainViewModel,这里要使用之前的数据绑定基类BindableBase(参考WPF之数据绑定基类),代码如下:

class MainViewModel:BindableBase
{
public bool CanExecute { get; set; }

private string tipText;
public string TipText 
{
    get { return tipText; }
    set { SetProperty(ref tipText, value); }
}

public DelegateCommand LoadedCommand { get; }

public DelegateCommand<MouseEventArgs> MouseMoveCommand { get; }


public MainViewModel()
{
    LoadedCommand = new DelegateCommand(() => { MessageBox.Show("程序加载成功");});

    MouseMoveCommand = new DelegateCommand<MouseEventArgs>(e =>
    {
        TipText = "鼠标当前位置:" + e.GetPosition(e.Device.Target).ToString();
    },
    e =>CanExecute);
}

}
界面的XAML代码如下:

<i:Interaction.Triggers>
<i:EventTrigger EventName=“Loaded”>
<i:InvokeCommandAction Command="{Binding LoadedCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName=“MouseMove”>
<local:EventCommandAction Command="{Binding MouseMoveCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>


public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
运行程序,效果如下:

扩展:基于InvokeCommandAction源码的实现(推荐)#
可以在InvokeCommandAction源码基础改动一下Invoke方法,实现我们的需求,改动如下:

protected override void Invoke(object parameter)
{
if (base.AssociatedObject != null)
{
if (CommandParameter != null)
parameter = CommandParameter;
ICommand command = ResolveCommand();
if (command != null && command.CanExecute(parameter))
{
command.Execute(parameter);
}
}
}
重写的RewriteInvokeCommandAction类完全可以替代上面的EventCommandAction,完整版代码如下:

public sealed class RewriteInvokeCommandAction : TriggerAction
{
private string commandName;

public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(RewriteInvokeCommandAction), null);

public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(RewriteInvokeCommandAction), null);

public string CommandName
{
	get
	{
		ReadPreamble();
		return commandName;
	}
	set
	{
		if (CommandName != value)
		{
			WritePreamble();
			commandName = value;
			WritePostscript();
		}
	}
}

public ICommand Command
{
	get
	{
		return (ICommand)GetValue(CommandProperty);
	}
	set
	{
		SetValue(CommandProperty, value);
	}
}

public object CommandParameter
{
	get
	{
		return GetValue(CommandParameterProperty);
	}
	set
	{
		SetValue(CommandParameterProperty, value);
	}
}

protected override void Invoke(object parameter)
{
	if (base.AssociatedObject != null)
	{
		if (CommandParameter != null)
			parameter = CommandParameter;
		ICommand command = ResolveCommand();
		if (command != null && command.CanExecute(parameter))
		{
			command.Execute(parameter);
		}
	}
}

private ICommand ResolveCommand()
{
	ICommand result = null;
	if (Command != null)
	{
		result = Command;
	}
	else if (base.AssociatedObject != null)
	{
		Type type = base.AssociatedObject.GetType();
		PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
		PropertyInfo[] array = properties;
		foreach (PropertyInfo propertyInfo in array)
		{
			if (typeof(ICommand).IsAssignableFrom(propertyInfo.PropertyType) && string.Equals(propertyInfo.Name, CommandName, StringComparison.Ordinal))
			{
				result = (ICommand)propertyInfo.GetValue(base.AssociatedObject, null);
			}
		}
	}
	return result;
}

}
USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值