2010年8月16日 星期一

Silverlight Data Binding中的Static Resources Binding

最近我在上課中曾經提到,Silvelright的Data Binding機制是如何地與過去ASP.NET和WinForm不同,這一部分一直是我非常熱愛Silverlight技術的原因,從最簡單的Data Binding機制,到Validation然後是data annotation,接著是Element to Element Binding,各式各樣精彩豐富的資料處理機制和效果,全部都藉著Data Binding技術來實現,連MVVM裡面都有Data Binding的影子...

而Silvelright技術的Data Binding又和ASP.NET/WebForm如此的不同,叫人又愛又恨,愛的是它功能之強大,幾乎可以說是貫串整個Silverlight開發架構,而讓人討厭的則是他和過去ASP.NET與WinForm時代的data Binding有那麼些許的不同。

然而,不管怎麼說,學習Silverlight時Data Binding絕對是你無法忽視的一大塊重要領域。這也是我Silvelright 4.0新書中花了將近萬把字很認真很努力的把Data Binding說個仔細的原因。雖然如此,我最喜歡的還是在課堂上和學員們分享Silverlight的Data Binding技術,上一期課程的學員應該可以很明顯的感受到,我們在Data Binding和N-tier架構概念的介紹所花的時間與精力。

原因都只有一個,因為Silverlight的data Binding非常、非常重要!

同時間由於VS2010開始支援Silvelright的所視即所得設計,你會發現我們可以在VS2010中點選某個UI物件,物件的幾乎每一個屬性都可以設定Binding,而除了Element To Element Binding之外,讀者一定常常看到在微軟官網介紹的Silvelright應用程式中,常常利用Data Binding技術Bind到一個或多個Static Resources。

這種場合相當特別,一般來說,我們在ASP.NET/WinForm是沒有這種概念的,Data Binding 繫結到的資料來源都是後面(後端,例如DB)傳過來的,但Silverlight的Data Binding由於是Bind到一個Object,所以可以寫程式new一個Object,然後Bind起來。

可是,往往我們這樣做會很麻煩,Binding動作會被切分成兩段,一段是在XAML碼上面寫Markup Binding指令,另外一段是寫程式new一個object或一個Collection,接著藉由設定UI Element的DataContext屬性或ItemsSource屬性來進行Binding。

有沒有可能,我們可以透過UI XAML描述就可以new出一個物件,並且進行Binding呢? 當然可以,例如,我設計了一個類別如下(請留意這個類別實作了INotifyPropertyChanged),它表達一筆資料:
namespace BasicDataBinding
{
//一筆資料的類別結構
public class AddressBookItem : System.ComponentModel.INotifyPropertyChanged
{
private string _Cname;
/// 姓名
public string Cname
{
get { return _Cname; }
set { _Cname = value; (...略...) }
}
private string _Tel;
///
/// 電話
///

public string Tel
{
get { return _Tel; }
set { _Tel = value; (...略...)}
}
private string _Address;
///
/// 地址
///

public string Address
{
get { return _Address; }
set { _Address = value; (...略...) }
}
//實作事件
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
//觸發事件用函式
public void NotifyPropertyChanged(string propertyName)
{
(...略...)
}
}
}

然後我設計該類別的集合(請注意繼承自ObservableCollection):
namespace BasicDataBinding
{
//繼承ObservableCollection泛型類別
//表達一堆AddressBookItem的資料集合
public class AddressBooks : System.Collections.ObjectModel.ObservableCollection
{
(...略...)
}
}
請留意namespace都在BasicDataBinding。

好了,有了這些個類別之後,我們可以透過撰寫底下程式碼來建立DataForm與data之間的DataBinding,例如:
//宣告資料存放物件集合
AddressBooks data=new AddressBooks();
//將資料與DataForm繫結
this.dataForm1.ItemsSource = data;
但這樣要寫程式碼,如果是初階程式設計師,或是Designer,或是痛恨寫Code的開發人員,會覺得這樣太痛苦。不能透過VS2010或Blend在XAML上拖拖拉拉設定一下就完成Data Binding嗎? 可以。

請先在XAML上註冊一下這個namespace:
<UserControl x:Class="BasicDataBinding.MainPage"
xmlns:LocalData="clr-namespace:BasicDataBinding">

然後在Resources區段宣告它:

<UserControl.Resources>
<LocalData:AddressBooks x:Key="MyAddressBooks">
</LocalData:AddressBooks>
</UserControl.Resources>

這樣的宣告,就等同於你new一個AddressBooks,並命名為MyAddressBooks,例如

AddressBooks MyAddressBooks=new MyAddressBooks();

但不一樣的是,在XAML中的宣告:
1.它是resource,便於管理或重用。
2.它可以被VS2010看得懂,並且在設計階段就透過Wizard來進行Binding。

所以,這樣我們在XAML中等同於new了一個ddressBooks集合物件,名稱為MyAddressBooks,如此一來,我們可以直接針對DataForm的ItemsSource屬性進行Apply Binding:

在Wizard中只需要透過設定的方式即可:

這樣的概念和技巧在Silverlight當中常常被用到。一開始的時候我發現很讓人難懂,特別是有ASP.NET或WinForm經驗的學員不容易明白Silverlight的Binding是怎麼回事,因為你會發現DataForm的XAML碼中,資料繫結指令是:
<toolkit:DataForm Margin="12,180,354,12" Name="dataForm1" ItemsSource="{Binding Source={StaticResource MyAddressBooks}}" />

就這麼一行,它告訴你繫結到StaticResource MyAddressBooks,但StaticResource MyAddressBooks又是從哪來的呢? 即便你找到前面宣告的

<UserControl.Resources>
<LocalData:AddressBooks x:Key="MyAddressBooks">
</LocalData:AddressBooks>
</UserControl.Resources>
又很難理解LocalData這個namespace又是從何而來的,裡面的AddressBooks又在哪?...???

但是老外撰寫這一類的Silverlight範例特多,有時候又沒解釋清楚,常常讓開發人員只看範例會搞不清楚到底是怎麼回事,但,其實理解後發現也不是很困難,這卻是一個相當簡單卻很好用的概念。Silverlight把過去我們在TechED提到過的『宣告式語法』概念發揮的淋漓盡致,不只是宣告一個UI,甚至可以宣告一個物件(Object),而記憶體中的物件和Silvelright的UI Control又可以Binding,這又是Silvelright與WPF的獨特之處。

用慣了之後,讓人真的很enjoy~

2 則留言:

愛玩の傑米哥 提到...

很實用的方法
受教了
謝謝

雷德FB 提到...

這種Binding方式超正點的
可以做出很多夢幻的效果
(例如一次將想秀的東西丟給一個UserControl元件,不需要寫啥程式碼一下子全部都自動連繫上了)