使用命令绑定是实现mvvm的重要途径,而Behavior,Trigger更是大大的简化这种方式,相信使用过 Behavior,Trigger的朋友深有体会,而 Trigger得灵活性之强又大大节省了很多的工作量,并且加速了编程效率。那么Behavior,Trigger,TriggerAction是如何实现的,使用过程中又要注意些什么?看我下面的分析。
Behavior,Trigger,TriggerAction都继承于IAttachedObject接口和DependencyObject,下面是IAttachedObject的源码:
[代码]c#/cpp/oc代码:
public interface IAttachedObject
{
void Attach(DependencyObject dependencyObject);
void Detach();
DependencyObject AssociatedObject { get; }
}
AssociatedObject是被关联的对象,注意这是DependencyObject类型的,不是所有的对象都可以被关联。Behavior,Trigger,TriggerAction中都会保留有这个对象。
Attach在被关联时会被调用,dependencyObject是被关联的对象。
Detach在被解除关联是调用。
在被关联是看看Behavior,Trigger,TriggerAction中内部实现的不同:
[代码]c#/cpp/oc代码:
public void Attach(DependencyObject dependencyObject)
{
if (dependencyObject != this.AssociatedObject)
{
if (this.AssociatedObject != null)
{
throw new InvalidOperationException(...);
}
if ((dependencyObject != null) && !this.AssociatedObjectTypeConstraint.IsAssignableFrom(dependencyObject.GetType()))
{
throw new InvalidOperationException(...);
}
this.associatedObject = dependencyObject;
this.OnAttached();
}
}
以上是TriggerAction的实现。Trigger实现如下:
[代码]c#/cpp/oc代码:
public void Attach(DependencyObject dependencyObject)
{
if (dependencyObject != this.AssociatedObject)
{
if (this.AssociatedObject != null)
{
throw new InvalidOperationException(...);
}
if ((dependencyObject != null) && !this.AssociatedObjectTypeConstraint.IsAssignableFrom(dependencyObject.GetType()))
{
throw new InvalidOperationException(...);
}
this.associatedObject = dependencyObject;
this.Actions.Attach(dependencyObject);
this.OnAttached();
}
}
相比TriggerAction多了一行 this.Actions.Attach(dependencyObject)。Actions是TriggerAction的集合,在Trigger被关联的同时会一次关联集合众的TriggerAction。
Behavior实现如下:
[代码]c#/cpp/oc代码:
public void Attach(DependencyObject dependencyObject)
{
if (dependencyObject != this.AssociatedObject)
{
if (this.AssociatedObject != null)
{
throw new InvalidOperationException(...);
}
if ((dependencyObject != null) && !this.AssociatedType.IsAssignableFrom(dependencyObject.GetType()))
{
throw new InvalidOperationException(...);
}
this.associatedObject = dependencyObject;
this.OnAssociatedObjectChanged();
this.OnAttached();
}
}
Behavior多了一行AssociatedObjectChanged通知外界关联对象发生了改变。由上面的代码可以看出,3着实现大体相同,对象一但被附加,在被解除关联之前不可以被改变,并且被附加的类型与指定的类型相一致。
Behavior,Trigger,TriggerAction这三者的区别与关联
Trigger与TriggerAction是从属的关系, Trigger 中保留有 TriggerAction 的集合,当 Trigger 被触发时,就会依次调用集合中的TriggerAction中的Invoke函数分别处理。 TriggerAction 中的Invoke是一个纯虚函数,这个函数中实现需要实现自己的逻辑代码。从TriggerBase继承的类可以调用InvokeActions来触发TriggerAction 的执行,以下是InvokeActions的实现:
[代码]c#/cpp/oc代码:
protected void InvokeActions(object parameter)
{
if (this.PreviewInvoke != null)
{
PreviewInvokeEventArgs e = new PreviewInvokeEventArgs();
this.PreviewInvoke(this, e);
if (e.Cancelling)
{
return;
}
}
foreach (System.Windows.Interactivity.TriggerAction action in this.Actions)
{
action.CallInvoke(parameter);
}
}
当Trigger被触发时,会调用PreviewInvoke事件通知外界已被触发。这是一条广播链,当外界设置e.Cancelling=true时,Actions中所有 TriggerAction 都不会执行。wp中所有广播链都是采用的这种模式,当设置 e.Cancelling=true是广播并不会停止,但是会组织后续逻辑的执行。
Behavior则没有特别的实现,在被关联时刻对被关联对象做任意的处理, Trigger 也一样。 Behavior 与 Trigger 的区别在于Trigger 可以通知到外界做额外的处理。所以 Behavior 与 Trigger 的功能是有重叠的,个人认为 Trigger 完全可以在Behavior 的基础上实现,由于Trigger 中Actions的存在,所以 Trigger 的灵活性和扩展性强于 Behavior 。
Behavior,Trigger,TriggerAction如何使用我就不额外说明了,不会用的就多搜索,网上的示例很多。
额外补充:System.Windows.Interactivity中仅有EventTrigger这一种 Trigger ,但是windows phone中提供了额外扩展的Behavior,Trigger和TriggerAction,在Microsoft.Phone.Interop.dll中,从引用中添加即可。
使用注意事项: Behavior,Trigger,TriggerAction 经常在xmal中使用,并且都附加到了控件上,但是需要注意的是这3着不在可视化树种,所以绑定的时候无法直接使用ElementName这个属性。我有一种解决方案可以解决这个问题,在以后的博客中说明。
要想最大化发挥Behavior,Trigger,TriggerAction的功效,仅仅使用官方提供的是不够,而自己定制才能将这三着的功能最大化发挥。如何订制就看我以后的博客吧。
说一下win8中的Behavior,Trigger,TriggerAction,win8官方并没有这样的功能,要使用需要额外下载第三方库,在NuGet管理中搜索Interactivity即可获得,不过库的名称为Windows.Ui.Interactivity.