深刻淺出WPF(10)——「腳踩N條船」的多路Binding
小序:
經過前面幾個章節的學習,咱們已經瞭解了Data Binding的基本常識和簡單的使用方法。今天讓咱們更進一步,學習一下多路Data Binding。
說實話,起「腳踩N條船」這個標題,實在有點不雅,可爲了讓你們記憶方便,我也管不了那麼多鳥~~~那麼什麼是多路Binding、它有什麼用、怎麼用呢?
正文:
讓咱們分析這樣一個需求——UI上有若干個文本框和一個「提交」按鈕,這些文本框都是用戶必須填寫的,若是不都填寫,提交按鈕是不可用的。
習慣了使用WinForm的同窗可能腦子裏已經開始飛速地搜尋使用Event來解決的方案了。實際上,在WPF裏使用多路Data Binding將很是簡單。
所謂「多路Binding(也能夠叫複合Binding)」就是指某個元素的Dependency Property的值不是由單一的數據源來決定,而是由多個數據源(經過必定邏輯)共同決定的,咱們通常會把邏輯寫在Converter裏。是否是很有些「腳踩N條船」的意思?
多路Binding使用的類是MultiBinding類,這個類實
際上就是對一組Binding對象的包裝——本質上並無影響Binding是「一對一」的基本理論。
下面讓咱們動手實現這個例子,由於你們已經對WPF的基本編程很熟悉了,因此我只把核心代碼寫在下面(又一次,我違反代碼維護性原則,把它們寫在了窗體的構造程序中)。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
-
- namespace MultiBindingSample
- {
-
- public partial class Window1 : Window
- {
- public Window1()
- {
- InitializeComponent();
-
-
- Binding b1 = new Binding("Text") { Source = this.textBox1 };
- Binding b2 = new Binding("Text") { Source = this.textBox2 };
- Binding b3 = new Binding("Text") { Source = this.textBox3 };
- Binding b4 = new Binding("Text") { Source = this.textBox4 };
-
-
- MultiBinding mb = new MultiBinding();
- mb.Bindings.Add(b1);
- mb.Bindings.Add(b2);
- mb.Bindings.Add(b3);
- mb.Bindings.Add(b4);
-
-
- mb.Converter = new SubmitEnableConverter();
- mb.Mode = BindingMode.OneWay;
-
-
- this.button1.SetBinding(Button.IsEnabledProperty, mb);
- }
- }
-
- public class SubmitEnableConverter : IMultiValueConverter
- {
-
- public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
-
- return !values.Cast<string>().Any(text => string.IsNullOrEmpty(text));
- }
-
-
- public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
- {
- throw new NotImplementedException();
- }
- }
- }
整個程序並無什麼難理解的,與咱們之前學習的Binding最大的區別就在它的Converter上,這回使用的Converter,其基接口是IMultiValueConverter,而不是先前咱們使用的IValueConverter。這個接口仍然只有兩個函數須要實現一下。又由於咱們此次使用的是OneWay模式,因此,代碼中只有Convert函數中包含邏輯。
請你們注意,Convert函數中最重要的就是它的values參數。這個參數是一個數組,這個數組裏包含的就是從一對一子Binding裏送來的值(在咱們的程序裏,就是4個TextBox的Text屬性值)。
數組是可被索引的,這就意味着values裏面的值是有順序的!那麼這個順序是什麼呢?
這個順序就是你調用MultiBinding.Bindings.Add(...)添加子Binding順序——
我認爲這裏是多路Binding一個小小的敗筆——這樣,寫出來的代碼會比較脆弱、順序不能變,並且比較隱晦。換句話說,後來的程序員若是改變一下Add的順序,就有可能致使程序出現很難測出的bug。
本例中,values[0]對應的是textBox1.Text屬性值、values[1]對應的是textBox2.Text屬性值、values[2]對應的是textBox3.Text屬性值、values[3]對應的是textBox4.Text屬性值。
而後,我使用Lambda表達式,判斷了一下是否有某個TextBox值是空的,對這個值取反,就是Submit Button.IsEnable的值。
運行效果以下:
邏輯進階
如今客戶的需求變了。要求是,前兩個文本框的內容一致、後兩個文本框內容一致,這時候Submit才亮(這在註冊新用戶的時候常常遇到)。
要是在WinForm中使用Event實現,就會有多處事件處理函數有變動,而在這個例子中,咱們只需改一兩句代碼就OK了。下面的代碼中,我優化了格式——項目中推薦這樣的格式。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
-
- namespace MultiBindingSample
- {
-
-
-
- public partial class Window1 : Window
- {
- public Window1()
- {
- InitializeComponent();
-
- InitializeBindings();
- }
-
- private void InitializeBindings()
- {
-
- MultiBinding mb = new MultiBinding() { Mode = BindingMode.OneWay, Converter = new SubmitEnableConverter() };
- mb.Bindings.Add(new Binding("Text") { Source = this.textBox1 });
- mb.Bindings.Add(new Binding("Text") { Source = this.textBox2 });
- mb.Bindings.Add(new Binding("Text") { Source = this.textBox3 });
- mb.Bindings.Add(new Binding("Text") { Source = this.textBox4 });
-
-
- this.button1.SetBinding(Button.IsEnabledProperty, mb);
- }
- }
-
-
- public class SubmitEnableConverter : IMultiValueConverter
- {
-
- public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
-
- if (!values.Cast<string>().Any(text => string.IsNullOrEmpty(text))
- && values[0].ToString() == values[1].ToString()
- && values[2].ToString() == values[3].ToString())
- {
- return true;
- }
- return false;
- }
-
-
- public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
- {
- throw new NotImplementedException();
- }
- }
- }
運行效果以下:
最後,但願你們玩兒的開心!也但願明天即將開幕的奧運會圓滿、順利!
OVER