深入理解MVVM模式中Silverlight的Trigger、Action和Behavior及Silverlight的繼承機制

雲霏霏發表於2014-09-30

  接觸Silverlight已經有兩三個月了,開始一直感覺他和Winform很相似,拖拖控制元件就行了,所以一直把經歷放在了研究後臺和伺服器互動和效能優化上面,很少去仔細研究Silverlight的頁面。前幾天,公司突然讓修改一個Winform的專案,再回過頭來看Winform,有種"不堪回首"的感覺。

  十一長假即將來臨,在這裡先祝大家假期快樂。今天難得有空,抽出點時間研究了一下Silverlight的繼承和觸發器,拿出來和大家分享一下。Silverlight和WPF中頁面佈局使用的都是XAML,頗為相似,學習WPF的也可以參考一下。

 

一、Silverlight中的繼承                                                                             

  那麼先來說一下Silverlight中的繼承吧,我們經常在後臺程式碼中使用繼承,實現程式碼的重用。那麼在前端頁面是否可以使用繼承,實現程式碼和控制元件的重用呢?答案是可以的。通過學習繼承,我們可以更深入的理解XAML。下面來寫一個Demo,一起來看一下,首先新建一個Silverlight專案,名字就叫SLDemo吧,新增預設的網站,建完專案後目錄如下:

既然要說繼承,那麼首先要有個父類,新加一個Class,名字就叫BaseView,新增一些屬性,程式碼如下:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SLDemo
{
   public class BaseView : UserControl
   {
      public string Title { get; set; }
      public int WinWidth { get; set; }
      public int WinHeight { get; set; }
   }
}

這裡簡單新增一些屬性,我們看到所有的頁面控制元件都繼承自UserControl,所以我們這個父類也要繼承UserControl,然後修改MainPage程式碼,來繼承我們這個類。

這裡要注意的是,Silverlight裡面頁面和後臺cs檔案要繼承自同一個父類,所以前端和後臺都要改,後臺cs檔案很簡單,修改後程式碼如下:

namespace SLDemo
{
   public partial class MainPage : BaseView
   {
      public MainPage()
      {
         InitializeComponent();
      }
   }
}

只是把父類UserControl改成BaseView即可,然後來看前端頁面的修改方法:

<sld:BaseView x:Class="SLDemo.MainPage"
    xmlns:sld="clr-namespace:SLDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="400" d:DesignWidth="600">

    <Grid x:Name="LayoutRoot" Background="White">
      
   </Grid>
</sld:BaseView>

 

來看一下程式碼變成什麼樣了?是不是和之前大不一樣了,<Usercontrol></Usercontrol>沒有了?是不是有種"高大尚"的感覺,瞬間感覺讓人看不懂了?下面我來解釋一下:

注意看第二行,我們引入了一個名稱空間,XAML中引入名稱空間就是 

xmlns:{字首}="clr-namespace:{名稱空間}"

這裡我們把字首寫成了sld(SLDemo的前三個字母),然後把Usercontrol改成我們的BaseView,和後臺cs檔案統一。實際上,XAML中應該這樣寫:

<名稱空間:類名></名稱空間:類名>

但是由於Usercontrol是系統預設的,所以前面的名稱空間就省了。接下來,先拖幾個控制元件上去看看,會發生什麼,這裡拖一個TabControl和一個Button吧,程式碼如下:

<sld:BaseView x:Class="SLDemo.MainPage"
    xmlns:sld="clr-namespace:SLDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="400" d:DesignWidth="600" 
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">

    <Grid x:Name="LayoutRoot" Background="White">
      <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="308,119,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
      <sdk:TabControl Height="100" HorizontalAlignment="Left" Margin="210,205,0,0" Name="tabControl1" VerticalAlignment="Top" Width="200" />
   </Grid>
</sld:BaseView>

可以看到,Button和之前一樣,tabcontrol和之前還是一樣(都要引用名稱空間),這裡主要說一下名稱空間,可以看到上面多了一行程式碼:

 xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
這裡引入TabControl的名稱空間,看我標紅的,然後用這個字首去新增Tabcontrol,所以以後我們引用自己的自定義控制元件也是這樣,先引用命名控制元件,然後通過字首來訪問。
  當然,寫了這麼多,我們還是再寫一個控制元件,其實Silverlight中Page大多用來顯示控制元件,頁面都是由控制元件堆出來的,然後在窗體顯示時,設定他的Content屬性來呈現。
到這裡,大家就可以通過繼承來重寫和擴充套件控制元件了。(今天先說到這裡,以後會詳細介紹開發自定義控制元件)。

二、Silverlight的Trigger、Action和Behavior                                   

 現在比較流行用MVVM來開發Silverlight專案,目的是實現XAML和程式碼的分離。今天就來說一下Trigger、Action和Behavior.

首先來說一下三者的關係:

Trigger : 觸發器,就像他的名字一樣,是用來監聽事件,然後執行某段程式碼

Action: 動作,就是執行一段程式碼

Behavior: 行為,看起來好像不太好理解,其實他可以看作是Trigger和Action的組合

首先來說一下Trigger和Action吧,首先來寫一個Action,新建一個類MyAction,在寫程式碼之前,我們要先引入一個名稱空間,如圖:

然後在程式碼中引用名稱空間System.Windows.Interactivity;繼承TriggerAction類,程式碼如下:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;

namespace SLDemo
{
   public class MyAction : TriggerAction<DependencyObject>
   {
      protected override void Invoke(object parameter)
      {
         MessageBox.Show("你觸發了一個Action!");
      }
   }
}

這裡我們重寫了Invoke方法,讓他彈出一條訊息。下面我們來使用這個Action,讓他來響應一個事件,修改XAML程式碼如下:

<sld:BaseView x:Class="SLDemo.MainPage"
    xmlns:sld="clr-namespace:SLDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    mc:Ignorable="d"
    d:DesignHeight="400" d:DesignWidth="600" 
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">

    <Grid x:Name="LayoutRoot" Background="White">
      <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="308,119,0,0" Name="button1" VerticalAlignment="Top" Width="75">
         <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
               <sld:MyAction />
            </i:EventTrigger>
         </i:Interaction.Triggers>
      </Button>
     
   </Grid>
</sld:BaseView>

這裡我們給一個按鈕新增了一個Trigger來偵聽單擊事件,然後繫結MyAction,執行後我們單擊按鈕,會彈出訊息框。

下面,我們來給Action傳遞一個引數,當然你可以多加幾個,我們就傳遞一個BtnName屬性吧,修改MyAction程式碼如下:

namespace SLDemo
{
   public class MyAction : TriggerAction<DependencyObject>
   {
      public string BtnName { get; set; }
      protected override void Invoke(object parameter)
      {
         MessageBox.Show("你觸發了一個Action!按鈕名稱是:" + this.BtnName);
      }
   }
}

我們只是新增了一個屬性,下面來看看如何使用:

執行效果如下:

我們就像平常寫XAML那樣,寫一個屬性就可以傳遞一個引數到Action裡面,當然這裡也可以繫結一個變數。但是實際開發中,我們不需要這樣做,因為我們把變數寫在ViewModel中,寫Action可以給一些Combox繫結SelectedChanged事件,目的還是實現佈局和程式碼分離。

 

Behavior

下面來看一下神奇的Behavior吧,有了Behavior,可以實現一些特效的重複使用,下面來寫一個簡單的例子看一下,就寫一個關於Textbox的吧,新建一個類,名字叫做TextboxBehavior,程式碼如下:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;

namespace SLDemo
{
   public class TextboxBehavior : Behavior<TextBox>
   {
      protected override void OnAttached()
      {
         base.OnAttached();
         AssociatedObject.TextChanged += new TextChangedEventHandler(AssociatedObject_TextChanged);
      }

      void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e)
      {
         if (AssociatedObject.Text.Length < 6)
         {
            AssociatedObject.Foreground = new SolidColorBrush(Color.FromArgb(200, 255, 0, 0));
         }
         else
         {
            AssociatedObject.Foreground = new SolidColorBrush(Color.FromArgb(200, 0, 255, 0));
         }
      }
   }
}

然後在XAML中新增如下程式碼:

這個時候,Textbox就繫結了我們的TextboxBehavior了,執行看下效果:

當輸入的內容小於六個字元的時候,顯示紅色

 

大於等於六個字元時就變成綠色。

我們一旦寫好了這個Behavior,所有頁面的Textbook都可以使用,是不是感覺很強大!原始碼已經上傳,在下面下載。

 

點選這裡下載原始碼

 

相關文章