有經驗的Windows程序員一定對寫代碼從一個控件上取值,以及把值存儲到控 件上很熟悉:
public Form1 : Form
{
private MyType myDataValue;
private TextBox textBoxName;
private void InitializeComponent( )
{
textBoxName.Text = myDataValue.Name;
this.textBoxName.Leave += new
System.EventHandler( this.OnLeave );
}
private void OnLeave( object sender, System.EventArgs e )
{
myDataValue.Name = textBoxName.Text;
}
}
這太 簡單了,正如你知道的,重復代碼。之所以不喜歡這樣重復代碼,就是因為應該 有更好的方法。是的,.Net框架支持數據綁定,它可以把一個對象的屬性映射到 控件的屬性上:
textBoxName.DataBindings.Add ( "Text",myDataValue, "Name" );
上面的 代碼就把textBoxName控件的“Text”屬性上綁定了MyDataValue對象 的"Name"屬性。在內部有兩個對象,綁定管理(BindingManager)和流 通管理(CurrencyManager), 實現了在控件與數據源之間的傳輸實現。你很可能 已經見過為種結構的例子,特別是在DataSet和DataGrid之間的。你也很可能已 經做過數據綁定的例子。你很可能只在表面上簡單的使用過從數據綁定上得到的 功能。你可以通過高效的數據綁定避免寫重復的代碼。
關於數據綁定的 完整處理方案可能至少要花上一本書來說明,要不就是兩本。Windows應用程序 和Web應用程序同時都支持數據綁定。比寫一個完整的數據綁定論述要強的是, 我確實想讓你記住數據綁定的核心好處。首先,使用數據綁定比你自己寫代碼要 簡單得多。其次,你應該在對文字元素通過屬性來顯示時,盡可能的使用它,它 可以很好的綁定。第三,在Windows窗體中,可以同步的對綁定在多控件上的數 據,進行相關數據源的檢測。
例如,假設只要在數據不合法時,要求將 文字顯示為紅色,你可能會寫這樣的代碼:
if ( src.TextIsInvalid )
{
textBox1.ForeColor = Color.Red;
} else
{
textBox1.ForeColor = Color.Black;
}
這很好,但只要在文字源發生改變時,你要隨時調用這段代碼。 這可能是在用戶編輯了文字,或者是在底層的數據源發生改變時。這裡有太多的 事件要處理了,而且很多地方你可能會錯過。但,使用數據綁定時,在src對象 上添加一個屬性,返回恰當的前景顏色就行了。
另一個邏輯可能是要根 據文字消息的狀態,來設置值可變化為恰當顏色的值:
private Color _clr = Color.Black;
public Color ForegroundColor
{
get
{
return _clr;
}
}
private string _txtToDisplay;
public string Text
{
get
{
return _txtToDisplay;
}
set
{
_txtToDisplay = value;
UpdateDisplayColor( IsTextValid( ) );
}
}
private void UpdateDisplayColor( bool bValid )
{
_clr = ( bValid ) ? Color.Black : Color.Red;
}
簡單的添加綁定到文本框裡就行了:
textBox1.DataBindings.Add ("ForeColor",
src, "ForegroundColor");
當數據綁定配置好以後 ,textBox1會根據內部源對象的值,用正確的顏色來繪制文本。這樣,你就已經 大大減少了從源數據到控件的數據來回傳輸。不再須要對不同地方顯示不同顏色 來處理很多事件了。你的數據源對象保持對屬性的正確顯示進行跟蹤,而表單控 件對數據綁定進行控制。
通過這個例子,我演示了Windows表單的數據綁 定,同樣的在web應用程序中也是一樣的原則:你可以很好的綁定數據源的屬性 到web控件的屬性上:
<asp:TextBox id=TextBox1 runat="server"
Text="<%# src.Text % >"
ForeColor="<%# src.ForegroundColor % >">
這就是說,當你創建一個應用程序在UI上顯示的 類型時,你應該添加一些必須的屬性來創建和更新你的UI,以便用戶在必要時使 用。
當你的對象不支持你要的屬性時怎麼辦呢?那就把它封裝成你想要 的。看這樣的數據結構:
public struct FinancialResults
{
public decimal Revenue
{
get { return _revenue; }
}
public int NumberOfSales
{
get { return _numSales; }
}
public decimal Costs
{
get { return _cost;}
}
public decimal Profit
{
get { return _revenue - _cost; }
}
}
要求你在一個表單上以特殊的格式信息來顯示這些,如果收 益為負,你必須以紅色來顯示收益。如果薪水小於100,你應該用粗體顯示。如 果開銷在10千(1萬)以上,你也應該用粗體顯示。創建FinancialResults結構的 開發者沒有添加UI功能到這個結構上。這很可能是正確的選擇, FinancialResults應該限制它的功能,只用於存儲實際的值。你可以創建一個新 類型,包含UI格式化屬性,以及在FinancialResults結構中的原始的存儲屬性:
public struct FinancialDisplayResults
{
private FinancialResults _results;
public FinancialResults Results
{
get { return _results; }
}
public Color ProfitForegroundColor
{
get
{
return ( _results.Profit >= 0 ) ?
Color.Black : Color.Red;
}
}
// other formatting options elided
}
這樣,你就創建了一個簡單的數據結構來幫助你 所包含的數據結構來進行數據綁定:
// Use the same datasource. That creates one Binding Manager
textBox1.DataBindings.Add ("Text", src, "Results.Profit");
textBox1.DataBindings.Add ("ForeColor",src,”ProfitForegroundColor");
我已經創建了一個只讀的屬性,用於訪問核心的財政數據結構。這種構 造在你試圖支持對數據的讀寫操作時不能工作,FinancialResults結構是值類型 ,這就是說獲取訪問器不提供對存儲空間的訪問,它只是返回一個拷貝。這樣的 方式很樂意返回一個拷貝,而這樣的拷貝並不能在數據綁定中進行修改。然而, 如果你試圖對數據進行編輯時,FinancialResults類應該是一個類,而不是一個 結構(參見原則6)。做為一個引用類型,你的獲取訪問器返回一個內部存儲的引 用,而且可以被用戶編輯。內部的結構應該須要對存儲的數據發生改變時做出響 應。FinancialResults應該觸發事件來告訴其它代碼這一狀態的改變。
有一個很重要的事情要記住:把數據源用在同一表單中的所有相關控件上。使用 DataMember屬性來區別每個控件顯示的屬性。你可以像這樣寫綁定過程:
< /p>
// Bad practice: creates two binding managers
textBox1.DataBindings.Add ("Text",src.Results, "Profit");
textBox1.DataBindings.Add ("ForeColor",src,“rofitForegroundColor");
這會創建兩個綁定管理者,一個為src對象,另一個為src.Results對象。 每個數據源由不同的綁定管理者控制,如果你想讓綁定管理者在數據源發生改變 時,更新所有的屬性,你須要確保數據源是一致的。
你幾乎可以在所有 的Windows控件和web控件上使用數據綁定。在控件裡顯示的值,字體,只讀狀態 ,甚至是控件控件的位置,都可以成為綁定操作的對象。我的建議是創建類或者 結構,包含一些用戶要求的,以某種樣式顯示的數據。這些數據就是用於更新控 件。
另外,在簡單控件中,數據綁定經常出現在DataSet和DataGrids中 。這非常有用,你把DataGrid綁定到DataSet上,然後DataSet中所有的值就顯示 了。如果你的DataSet有多個表,你甚至還可以在多個表中間進行導航。這不是 很好嗎?
好了,下面的問題就是如果你的數據集不包含你想顯示的字段 時該怎麼辦。這時,你必須添加一個列到DataSet中,這一列計算一些UI中必須 的值。如果值可以用SQL表達式計算,那麼DataSet可以為你完成。下面的代碼就 添加了一個列到Employees 數據表中,用於顯示格式化了名字:
DataTable dt = data.Tables[ "Employees" ];
dt.Columns.Add( "EmployeeName",
typeof( string ),
"lastname + ', ' + firstname");
通過添加列到DataSet中,你可以添加這些列 到DataGrid上。你所創建的對象層,是在數據存儲對象的最項層上,用於創建數 據表現層給你的用戶。
到目前為止,這一原則裡所使用的都是string類 型,.net框架可以處理字符到數字的轉化:它試圖轉化用戶的輸入到恰當的類型 。如果失敗,原始的值會恢復。這是可以工作的,但用戶完全沒的反饋信息,他 們的輸出被安靜的忽略了。你可以通過處理綁定過程中的轉化事件來添加反饋信 息。這一事件在綁定管理者從控件上更新值到數據源時發生。ParseEventArgs包 含了用戶輸入的文字 ,以及它所期望被轉化的類型。你可以捕獲這一事件,其 後完成你自己的通知,也可以修改數據並且用你自己的值來更新數據:
private void Form1_Parse( object sender, ConvertEventArgs e )
{
try {
Convert.ToInt32 ( e.Value );
} catch
{
MessageBox.Show (
string.Format( "{0} is not an integer",
e.Value.ToString( ) ) );
e.Value = 0;
}
}
你可能還要處理 Format事件,這一個HOOK,可以在數據從數據源到控件時格式化數據。你可以修 改ConvertEventArgs的Value字段來格式化必須顯示的字符串。
.Net提供 了通用的框架,可以讓你支持數據綁定。你的工作就是為你的應用程序和數據提 供一些特殊的事件句柄。Windows表單和Web表單以及子系統都包含了豐富的數據 綁定功能。框架庫已經包含了所有你須要的工具,因此,你的UI代碼應該真實的 描述數據源和要顯示的屬性,以及在把這些元素存儲到數據源時須要遵守的規則 。你應該集中精力創建數據類型,用於描述顯示的參數,然後Winform以及 Webform的數據綁定完成其它的。不應該在把數據從用戶控件到數據源之間進行 傳輸時寫相關的代碼(譯注:指用數據綁定,而不用其它的方法)。不管怎樣,數 據必須從你的業務對象關聯到UI控件上與用戶進行交互。通過創建類型層以及使 用數據綁定的概念,你就可以少寫很多代碼。.Net框架已經 同時在Windows和 Web應用程序中為你處理了傳輸的工作。
返回教程目錄