建立一個資料繫結控制項也就是建立一個使用資料來源的控制項(當然,你必須提供一個資料來源給他使用)。
簡而言之,只要三個步驟:
- 繼承DataBoundControl
- 改寫PerformSelect(),從資料來源取得資料來源視圖(DataSourceView)
- 改寫PerformDataBinding(),將資料指定給控制項的屬性。
但細節方面,也有幾個地方要注意:
- 如果已經初始化資料繫結控制項,而資料來源在PreRender事件後變更,那麼就必須要執行OnDataPropertyChanged()方法。
- 如果是使用DataSourceID來指定資料來源,那麼必須在取得資料來源視圖後執行OnDataBinding()方法;
- 如果是使用DataSource來指定資料來源,則在取得資料來源視圖前執行OnDataBinding()方法。
- 需要設定資料繫結的狀態,以告訴類別是否需要設定其他的資料。
if (Initialized) //BaseDataBoundControl.Initialized{OnDataPropertyChanged(); //BaseDataBoundControl.OnDataPropertyChanged()}
if (!IsBoundUsingDataSourceID) //BaseDataBoundControl.IsBoundUsingDataSourceID{OnDataBinding(EventArgs.Empty); //Control.OnDataBinding()}GetData().Select(DataSourceSelectArguments.Empty,(data) => {if (IsBoundUsingDataSourceID)OnDataBinding(EventArgs.Empty);PerformDataBinding(data);});
RequiresDataBinding = false; //指出是否應該呼叫DataBind()方法MarkAsDataBound(); //將檢視狀態中的控制項狀態設為已成功繫結至資料OnDataBound(EventArgs.Empty); //引發 DataBound 事件
主要的程式碼如下:
其中[DefaultProperty("Text")][ToolboxData("<{0}:TextBoxSet runat=server></{0}:TextBoxSet>")]public class TextBoxSet : DataBoundControl{private IList _boxSet = null;public IList BoxSet{get{if (null == _boxSet){_boxSet = new ArrayList();}return _boxSet;}}public string DataTextField{get{object o = ViewState["DataTextField"];return (o == null) ? string.Empty : (string)o;}set{ViewState["DataTextField"] = value;//BaseDataBoundControl.Initialized//取得值,指出是否已初始化資料繫結控制項。if (Initialized){//BaseDataBoundControl.OnDataPropertyChanged()//在其中一個基底資料來源識別屬性變更之後,將資料繫結控制項重新繫結至其資料。//如果 DataSource、DataSourceID 或 DataMember 屬性值在發生頁面的 PreRender 事件後做了變更,則會呼叫 OnDataPropertyChanged 方法。OnDataPropertyChanged();}}}protected override void PerformSelect(){//BaseDataBoundControl.IsBoundUsingDataSourceID//取得值,指出 System.Web.UI.WebControls.BaseDataBoundControl.DataSourceID 屬性是否已設定。if (!IsBoundUsingDataSourceID){//Control.OnDataBinding()//引發 System.Web.UI.Control.DataBinding 事件。OnDataBinding(EventArgs.Empty);}//DataBoundControl.GetData()//擷取 System.Web.UI.DataSourceView 物件,執行資料作業時資料繫結控制項會使用它。//DataSourceView.Select()//從基礎資料儲存區非同步取得資料清單。GetData().Select(DataSourceSelectArguments.Empty, new DataSourceViewSelectCallback(OnDataSourceViewSelectCallback));//BaseDataBoundControl.RequiresDataBinding//取得或設定值,指出是否應該呼叫 System.Web.UI.WebControls.BaseDataBoundControl.DataBind()方法RequiresDataBinding = false;//DataBoundControl.MarkAsDataBound()//將檢視狀態中的控制項狀態設為已成功繫結至資料。MarkAsDataBound();//BaseDataBoundControl.OnDataBound//引發 System.Web.UI.WebControls.BaseDataBoundControl.DataBound 事件。OnDataBound(EventArgs.Empty);}private void OnDataSourceViewSelectCallback(IEnumerable data){if (IsBoundUsingDataSourceID)OnDataBinding(EventArgs.Empty);PerformDataBinding(data);}protected override void PerformDataBinding(IEnumerable data){//DataBoundControl.PerformDataBinding//在衍生類別中覆寫時,會將資料從資料來源繫結至控制項。base.PerformDataBinding(data);if (data != null){foreach (object dataItem in data){TextBox box = new TextBox();if (DataTextField.Length > 0){box.Text = DataBinder.GetPropertyValue(dataItem, DataTextField, null);}else{PropertyDescriptorCollection pdcs = TypeDescriptor.GetProperties(dataItem);box.Text = string.Empty;if (pdcs.Count >= 1){if (null != pdcs[0].GetValue(dataItem)){box.Text = pdcs[0].GetValue(dataItem).ToString();}}}BoxSet.Add(box);}}}protected override void Render(HtmlTextWriter writer){if (BoxSet.Count <= 0){return;}writer.RenderBeginTag(HtmlTextWriterTag.Ul);foreach (object item in BoxSet){TextBox box = item as TextBox;writer.RenderBeginTag(HtmlTextWriterTag.Li); //<li>writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");writer.AddAttribute(HtmlTextWriterAttribute.Value, box.Text);writer.RenderBeginTag(HtmlTextWriterTag.Input);writer.RenderEndTag(); //</>writer.RenderEndTag(); //</li>}writer.RenderEndTag();}
GetData().Select(DataSourceSelectArguments.Empty, new DataSourceViewSelectCallback(OnDataSourceViewSelectCallback));
也等同於GetData().Select(DataSourceSelectArguments.Empty, OnDataSourceViewSelectCallback);
或是
不過,我還是覺得使用new的方式比較好,可讀性佳,至少你會比較了解你到底是在處理哪一種類別。GetData().Select(DataSourceSelectArguments.Empty,(data) => {if (IsBoundUsingDataSourceID)OnDataBinding(EventArgs.Empty);PerformDataBinding(data);});
測試的網頁如下:
<asp:AccessDataSource ID="AccessDataSource1" runat="server"DataFile="~/App_Data/NorthWind.mdb"SelectCommand="SELECT [LastName] FROM [Employees]"></asp:AccessDataSource><cc1:TextBoxSet ID="TextBoxSet1" runat="server"DataSourceID="AccessDataSource1" /><hr /><asp:AccessDataSource ID="AccessDataSource2" runat="server"DataFile="~/App_Data/NorthWind.mdb"SelectCommand="SELECT * FROM [Employees]"></asp:AccessDataSource><cc1:TextBoxSet ID="TextBoxSet2" runat="server"DataSourceID="AccessDataSource2" DataTextField="FirstName" /><hr /><cc1:TextBoxSet ID="TextBoxSet3" runat="server" DataTextField="Name" /><hr />
使用的資料庫可自微軟下載:Access 2000 Tutorial: Northwind Traders Sample Database
其中第三個控制項使用DataSource做為資料來源,我們在Page_Load事件時提供給他
protected void Page_Load(object sender, EventArgs e){var data = new object[]{new {ProductId = 1, Name = "可可"},new {ProductId = 2, Name = "茶"},new {ProductId = 3, Name = "咖啡"}};this.TextBoxSet3.DataSource = data;this.TextBoxSet3.DataBind();}
測試結果:
參考資料:
沒有留言:
張貼留言