使用命令綁定是實現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.