WPF執行個體秀——不用屬性也Binding
本文:
實際編程中,因為我們較多地使用到Binding類的Source與Path,所以可能會有一個思維定式,那就是:有可能作為資料來源的類一定要準備好一些屬性,這些屬性將作為Binding的Path。
如果本著這個思想去設計有可能作為資料來源的類,那麼會有兩個問題出現:
1. 這個類的哪些屬性有可能作為資料來源的Path?是都需要激發NotifyPropertyChanged事件,還是用到了再添加?這很有可能讓這個類遲遲不能封閉。
2. 需要用屬性把一些方法封裝起來,用來暴露給Binding,造成冗餘和語義上的不美觀。
其實,WPF類庫裡有一個名為ObjectDataProvider的類就是專門為瞭解決這個矛盾的——有了這個類,你在設計自己的類的時候就不必總想著把它設計成資料來源的事兒了,該怎麼抽象就怎麼抽象、該怎麼封裝就怎麼封裝。
你可能會問:“如果這個類已經封閉了(不再改動)而我又需要拿它當資料來源了,碰巧所需要的資料是它某個方法的傳回值,沒有對應屬性,怎麼辦?”OK,這就是ObjectDataProvider的用武之地了——使用它,可以在你這個類的執行個體外面加上一層“封裝”(或者說是加個殼兒),使它變成一個標準的Binding資料來源。如果沒記錯的話,這應該是著名的“適配器模式”。
下面,我們用一段簡單的代碼來學習如何使用ObjectDataProvider。
這個例子簡單到不能再簡單——三個TextBox,在前兩個裡輸入合適的數字,在第三個裡會顯示它們的和。按照UI與邏輯分開的原則,計算加法的功能應該由某個類來實現。
後台負責計算的類是這樣:
- public class Calculator
- {
- public int Add(int arg1, int arg2)
- {
- return arg1 + arg2;
- }
- public string Add(string arg1, string arg2)
- {
- int x = 0;
- int y = 0;
- if (int.TryParse(arg1, out x) && int.TryParse(arg2, out y))
- {
- return this.Add(x, y).ToString();
- }
- else
- {
- return "Input Error!";
- }
- }
- }
大家看到了,設計這個類的時候,涉及到加法運算的邏輯時,任何一個程式員都會很自然地採用一個方法來實現,而不會為了把它做成一個Binding的資料來源專門把這些方法封裝進屬性裡——這樣就破壞了物件導向的抽象。
然後,讓我們看看如何使用ObjectDataProvider來封裝這個類。
- <Window x:Class="WpfApplicationAdd.Window1"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="clr-namespace:WpfApplicationAdd"
- xmlns:system="clr-namespace:System;assembly=mscorlib"
- Title="Add" Height="136" Width="230" Background="SteelBlue">
- <Window.Resources>
- <ObjectDataProvider x:Key="odp" ObjectType="{x:Type local:Calculator}" MethodName="Add">
- <ObjectDataProvider.MethodParameters>
- <system:String>0</system:String>
- <system:String>0</system:String>
- </ObjectDataProvider.MethodParameters>
- </ObjectDataProvider>
- </Window.Resources>
- <StackPanel>
- <TextBox x:Name="textBox1" Margin="5" Text="{Binding Source={StaticResource odp}, Path=MethodParameters[0], BindsDirectlyToSource=true, UpdateSourceTrigger=PropertyChanged}" />
- <TextBox x:Name="textBox2" Margin="5" Text="{Binding Source={StaticResource odp}, Path=MethodParameters[1], BindsDirectlyToSource=true, UpdateSourceTrigger=PropertyChanged}"/>
- <TextBox x:Name="textBox3" Margin="5" Text="{Binding Source={StaticResource odp}, Mode=OneWay}"/>
- </StackPanel>
- </Window>
運行起來之後,你就能看到這樣的結果了: