最近做的Silverlight項目上用到了大量的拖拽,自動跟隨等功能,由於趕時間,加上對Silverlight半生不熟,用的是最簡單也是最不好維護的方法。項目忙完了閑下來,想重構一下代碼,想起了Trigger和Action這兩個東西,當初接觸這兩個東西不深,只是認識,不知道用。現在正好可以好好學習一下,參考了重多大神的代碼之后,終於初步熟悉了它們。這里分享一下我對Trigger和Action的認識。
我用一個最簡單的例子來說明Action與Trigger,點擊一個Button彈出MessageBox。
建立一個Silverlight Application,引用System.Windows.Interactivity.dll程序集(這個程序集很重要,是使用Trigger,Action,Behavior必須引用的)。我們在MainPage里放一個Button並給一個Click事件。
xaml代碼如下:
1: <UserControl x:Class="SilverlightApplication1.MainPage"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6: mc:Ignorable="d"
7: d:DesignHeight="300" d:DesignWidth="400">
8:
9: <Grid x:Name="LayoutRoot" Background="White">
10: <Button Content="Button" HorizontalAlignment="Left" Margin="35,31,0,0" Name="button1" VerticalAlignment="Top" Click="button1_Click" />
11: </Grid>
12: </UserControl>
cs代碼如下:
1: public partial class MainPage : UserControl
2: {
3: public MainPage()
4: {
5: InitializeComponent();
6: }
7:
8: private void button1_Click(object sender, RoutedEventArgs e)
9: {
10: MessageBox.Show("Hello World!");
11: }
12: }
很簡單,這是最傳統的做法。
下面Action要上場了。所謂Action,就是去執行某些操作。可以根據需要創建自己的Action,常見的需要創建Action的情況有:改變屬性、調用方法、打開窗口、導航到某個頁面、設置焦點等。自定義Action可從 TriggerAction<DependencyObject>或TargetedTriggerAction<DependencyObject>繼承,區別在於操作對象是關聯對象還是特定的目標對象,實現時覆蓋Invoke方法即可。我們新建一個簡單的Action,代碼如下:
1: public class Action1 : TriggerAction<DependencyObject>
2: {
3: public Action1()
4: {
5:
6: }
7:
8: protected override void Invoke(object o)
9: {
10: MessageBox.Show("Hello World! This message comes from an action.");
11: }
12: }
在Invoke方法里Show一個MessageBox。這樣,一個Action這創建好了。如何使用它呢?看下面的代碼。
xaml代碼:
1: <UserControl x:Class="SilverlightApplication1.MainPage"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6: xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
7: xmlns:local="clr-namespace:SilverlightApplication1"
8: mc:Ignorable="d"
9: d:DesignHeight="300" d:DesignWidth="400">
10:
11: <Grid x:Name="LayoutRoot" Background="White">
12: <Button Content="Button" HorizontalAlignment="Left" Margin="35,31,0,0" Name="button1" VerticalAlignment="Top">
13: <i:Interaction.Triggers>
14: <i:EventTrigger EventName="Click">
15: <local:Action1 />
16: </i:EventTrigger>
17: </i:Interaction.Triggers>
18: </Button>
19: </Grid>
20: </UserControl>
運行結果如圖:
很顯然,Button的單擊調用了那個Action,Button不再去觸發xaml.cs里的那個事件處理方法了,而了觸發了之前新建的Action1。回到xaml代碼,EventTrigger是Silverlight自帶的一個觸發器(Trigger)。Trigger一量觸發,就會執行對應的Action。這里我們把Action1與EventTrigger關聯到一起(“關聯”這個詞可能用得不合適,反正就這個意思),EventTrigger觸發Click事件,執行Action彈出MessageBox。而xaml.cs文件里的代碼不再需要了。它的好處是不是已經看出來了?有效的分離了UI與后台代碼。
下面Trigger正式登場。所謂Trigger,就是監聽某些條件的變化,比如事件觸發,屬性值改變等,進而觸發一些動作的發生。這些Triggers可能是EventTrigger、CollisionTrigger 等,當然更多的或許是創建自己的Trigger。自定義Trigger只需要從TriggerBase<DependencyObject>繼承,並覆蓋OnAttached和OnDetaching方法即可。我面來創建一個Trigger。代碼如下:
1: public class Trigger1 : TriggerBase<Button>
2: {
3: protected override void OnAttached()
4: {
5: base.OnAttached();
6: this.AssociatedObject.Click += new RoutedEventHandler(Trigger1_Click);
7: }
8:
9: protected override void OnDetaching()
10: {
11: base.OnDetaching();
12: this.AssociatedObject.Click -= new RoutedEventHandler(Trigger1_Click);
13: }
14:
15: protected void Trigger1_Click(object sender, RoutedEventArgs e)
16: {
17: MessageBox.Show("Hello World! This message comes from a trigger.");
18: }
19: }
代碼中我們用到了AssociationObject這個屬性,這個屬性表示綁定Trigger的對象,這里是一個Button,OnAttached中注冊一個Click事件處理方法,OnDetching中取消注冊(如果不取消注冊,當這個Button上其它觸發器觸發時,這個觸發器的效果還會重現,因為Click觸發之后委托鏈上所有注冊方法都會執行, 具體情況具體分析是否需要取消注冊)。
在Xaml中這樣來使用這個Trigger:
1: <Grid x:Name="LayoutRoot" Background="White">
2: <Button Content="Button" HorizontalAlignment="Left" Margin="35,31,0,0" Name="button1" VerticalAlignment="Top">
3: <i:Interaction.Triggers>
4: <local:Trigger1 />
5: </i:Interaction.Triggers>
6: </Button>
7: </Grid>
運行如果如下:
這里Trigger1被觸發了。
其實,觸發器(Trigger)和動作(Action)是協同工作的。當某事件發生的時候,Trigger就會觸發並調用一個Action,Trigger和Action組成了最簡單的行為(Behavior下次再討論)表現形式。
最后,我們讓Trigger1和Action1協同工作一下。Trigger1的代碼改一改:
1: public class Trigger1 : TriggerBase<Button>
2: {
3: protected override void OnAttached()
4: {
5: base.OnAttached();
6: this.AssociatedObject.Click += new RoutedEventHandler(Trigger1_Click);
7: }
8:
9: protected override void OnDetaching()
10: {
11: base.OnDetaching();
12: this.AssociatedObject.Click -= new RoutedEventHandler(Trigger1_Click);
13: }
14:
15: protected void Trigger1_Click(object sender, RoutedEventArgs e)
16: {
17: InvokeActions(null);
18: }
19: }
Trigger1_Click方法里調用InvokeActions來執行“關聯”到這個Trigger上的Action。Xaml如下:
1: <Grid x:Name="LayoutRoot" Background="White">
2: <Button Content="Button" HorizontalAlignment="Left" Margin="35,31,0,0" Name="button1" VerticalAlignment="Top">
3: <i:Interaction.Triggers>
4: <local:Trigger1>
5: <local:Action1 />
6: </local:Trigger1>
7: </i:Interaction.Triggers>
8: </Button>
9: </Grid>
運行結果如下:
這里,Button綁定了Trigger1,Attach這個Trigger1時把Click事件注冊上(OnAttached方法。關於Attach,請參考“附加屬性”),所以單擊Button就調用了綁定在Trigger1上的Action1。
至於這兩個東西的好處就不必多說了,分離了UI與代碼,提高了代碼的復用。
好了,初學Trigger和Action,大致縷了一下它們之間的關系,就簡單介紹到這,歡迎一起討論。更神奇的Behavior將在下篇中介紹。
附上上面的源代碼