WPF資料繫結概觀(一)---控制項屬性繫結
我想任何應用程式多多少少都必須使用到資料,不管是資料庫、XML、文字或二進位檔案、簡單的集合物件或是其它控制項或元素的屬性,這都是我們時常會使用到的資料類型,因此如何讓WPF可以讀取不同的資料,甚至於在資料繫結的階段就能夠進行資料的篩選、組合,以及決定資料要如何顯示就成了開發WPF應用程式的一大課題。當然,和許多.NET技術一樣,我無法在短短的一篇文章裡就把WPF資料繫結的奧妙說明清楚,我想光是從簡單到進階的應用、WPF控制項的Datatemplate設計以及未來將加入下一版.NETFramework的一些預覽版的控制項(WPFToolkit中的DataGrid),就算我努力寫個10幾篇文章也不足以完全說明。
資料繫結是一種將控制項或元素連結到資料的技術,正如我們前面所言,資料可能是多種不同的類型,因此有時我們必須視需求來進行應用,而這裡所謂的
”應用”可能是需要自訂類別,也可能是必須自行撰寫ValueConverter,也有可能是使用多重繫結(Multi Binding)的技巧來產生一個與原始資料完全不同的結果,當然這是有許多應用上的可能,一開始我就從最基本的資料繫結談起。
如果是在Blend裡,將控制項屬性繫結至另外一個控制項是很簡單的,我舉一個簡單的例子來說明:
- 首先在window上佈置一個ProgressBar(名稱:progressBar)、TextBlock(名稱:tbValue)和Button項目。
- 選取TextBlock控制項後,在”屬性面板/一般屬性”找到Text屬性後,按下後方的”進階選項”,並在下拉選單中選取”資料繫結”。
- 在建立資料繫結方塊裡,先切換至元素屬性標籤頁,展開LayoutRoot就可以找到progressBar,點選progressBar再從屬性視窗挑選資料繫結的來源,在此我們先將TextBlock的Text屬性繫結至progressBar的Value屬性,選取後按下完成按鈕即可。
完成到這裡,如果你隨意改變progressBar的Value屬性就可以看到tbValue的Text也會自動顯示progressBar.Value的數值。
但這並不是我想要的結果,因為我們佈置了一個Button,我並不希望在一開始時就進行資料繫結,而是希望在使用者按下Button之後再進行資料繫結,這樣子就不會一載入TextBlock就顯示0,這並不好看,因此我們可以改用撰寫程式碼的方式來加入資料繫結。
首先請重設tbValue的Text,取消資料繫結,然後為Button加入Click事件並加入以下的程式碼:
{
Binding pbBinding = new Binding();
pbBinding.Source = progressBar;
pbBinding.Path = new PropertyPath(ProgressBar.ValueProperty);
tbValue.SetBinding(TextBlock.TextProperty, pbBinding);
}
在程式裡我們先建立Binding物件,並指定Source與Path屬性後再以TextBlock的SetBinding方法來進行資料繫結,而Path屬性為PropertyPath型別,因此我們以一個PropertyPath物件傳入屬性值即可,這是撰寫C#程式來建立資料繫結的方式。值得注意的是,SetBinding必須使用相依屬性來設定(在WPF中大部分以Set或Get為開頭的方法都是以相依屬性來設定,其中的原因為何?等我發表自訂相依屬性的文章時再來說明)
現在程式必須由使用者按下Button之後才會進行資料繫結,而我們怎麼知道在執行階段時資料繫結仍有作用?很簡單,請將程式碼修改如下來測試執行即可---
private void Button_Click(object sender, RoutedEventArgs e)
{
Binding pbBinding = new Binding();
pbBinding.Source = progressBar;
pbBinding.Path = new PropertyPath(ProgressBar.ValueProperty);
tbValue.SetBinding(TextBlock.TextProperty, pbBinding);
_timer.Interval = new TimeSpan(0, 0, 1);
_timer.Tick += new EventHandler(_timer_Tick);
_timer.Start();
}
void _timer_Tick(object sender, EventArgs e)
{
if (progressBar.Value < 100)
{
progressBar.Value += 1;
}
else
{
_timer.Stop();
}
}
以上的程式碼只是使用一個DispatcherTimer物件來觸發,每秒觸發一次Tick事件,因此若無意外,如果每秒鐘TextBlock的內容都會變更一次,那就表示資料繫結並不是OneTime(只繫結一次)。
不過這種效果大概還是很難讓人滿意,因為實際應用上我們不可能讓一個TextBlock只顯示進度數值,至少也得顯示個”目前進度75%”之類的,但是繫結的來源是直接繫結至ProgressBar的Value屬性,這是個double值,如何能夠讓TextBlock顯示非double值的資料呢?
這種時候就是使用值轉換器(value converter)的好時機了,關於值轉換器的問題,我想在下一篇文章再來說明如何建立專屬的值轉換器吧~
在dotblogs裡的高手如雲,這常會讓我對於介紹技術深淺程度的拿揑上常常會失去準頭,寫得太淺的文章怕貽笑大方;寫太深的文章又怕別人看不懂,淪為華而不實的技術賣弄,因此我想乾脆就由淺入深地發表一系列的文章來介紹資料繫結的技巧與應用。坦白地說,我和這裡的許多人一樣都是撰寫電腦書籍的作者,不過以往我並不撰寫微軟相關技術的書籍,唯一一本討論微軟技術的書籍就是以WPF技術為主題(四月份才會出版),礙於版權合約的問題,我不能將手上現有的稿子拿來發表,又加上我個人一向不太喜歡轉貼別人的文章來發表(萬一你碰巧買到我的書,又在我的部落格看到很類似的討論文章,請不要認為我是抄襲來的),因此關於這個議題我必須重新撰寫文章來討論,所以發表的速度可能不會很快,也希望各位體諒!