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~

留言

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

這個網誌中的熱門文章

原來使用 .net 寫個 MCP Server 如此簡單

使用LM Studio輕鬆在本地端以API呼叫大語言模型(LLM)

開啟 teams 中的『會議轉錄(謄寫)』與Copilot會議記錄、摘要功能

在VS Code當中使用 Azure DevOps MCP Server

原來使用 .net 寫個 MCP Client 也如此簡單