2009-06-11 22 views
10

我有一個用戶控件,它有多個我希望綁定到BindingSource的字段。我也想UserControl公開一些BindingSource屬性,以便它可以放在窗體上並綁定到窗體上的BindingSource。是否有捷徑可尋?我意識到我可以在其BindSource setter中重新綁定UserControl的所有控件。但這似乎是錯誤的。有沒有一些BindingSource代理可以讓我將用戶控件中的BindingSource鏈接到表單中的BindingSource?在用戶控件中使用BindingSource

+0

你也許可以通過寫一個屬性來暴露你的BindingSource.DataSource對象屬性,你可以調用DataSource,這會設置你的表單的BindingSource.DataSource屬性。否則,請嘗試進一步解釋您希望做什麼或給出一個可以幫助我們更好地理解的具體示例。當我讀到它時,我的頭腦仍然有點模糊。你想在設計時設置DataSource嗎?你想暴露屬性窗口中的BindingSource屬性嗎?您是否想要將您的UserControl控件綁定到BindingSource對設計進行更改的特定DataMember? – 2009-09-22 01:58:55

回答

5

根據你的問題,我很難得到你打算做的事情。因此,我會盡我所能爲您提供有關此事的有趣信息,我希望。

首先,讓我們考慮一下客戶管理軟件項目中的以下用戶控件。

public partial class CustomerManagementUserControl : UserControl { 
    public CustomerManagementUserControl() { 
     InitializeComponent(); 
     _customerBindingSource = new BindingSource(); 
    } 
    public IList<ICustomer> DataSource { 
     set { 
      _customerBindingSource.DataSource = value; 
     } 
    } 
    private BindingSource _customerBindingSource; 
} 

其次,我們來考慮下面的表格,它應該是您的客戶管理表單。

public partial class CustomerManagementForm : Form { 
    public CustomerManagementForm() { 
     InitializeComponent(); 
     _customerUserControl = new CustomerManagementUserControl(); 
     _customerUserControl.Name = @"customerUserControl"; 
    } 
    private void CustomerManagementForm_Load(object sender, EventArgs e) { 
     // CustomersFacade is simply a static class providing customer management features and requirements. 
     // Indeed, the GetCustomers() method shall return an IList<ICustomer>. 
     // The IList type and typed IList<T> are both intended to be bindable as a DataSource for DataBinding. 
     _customerUserControl.DataSource = CustomersFacade.GetCustomers(); 
     this.Controls.Add(_customerUserControl); 
    } 
    private CustomerManagementUserControl _customerUserControl; 
} 

如果你希望使用CustomerManagementUserControl.DataSource財產屬性窗口中,請考慮增加你的屬性定義的頂部以下。

[System.ComponentModel.DesignTimeVisible(true), System.ComponentModel.DesignerCategory("CustomerUserControl"), System.ComponentModel.Description("Sets the CustomerUserControl DataSource property")] 

這是我猜你可能想要做的一種方法。另一方面,如果你想要做的是通過設置一個不同類型的對象作爲你的UserControl.BindingSource.DataSource屬性來獲得儘可能最抽象的,那麼你將不得不編寫一個方法來檢測該對象已通過,然後相應地綁定屬性。或許,你可以去的一個好方法是通過Reflection,如果你願意的話。以任何可能的方式,您可能會想到使用這種多態性功能,您將不得不爲自己編寫一個所有可綁定對象必須實現的接口。這樣,您將避免未知的屬性名稱,並且什麼時候會來綁定您的UserControl的控件,您將能夠將正確的屬性綁定到正確的控件等等。

讓我們嘗試以下操作:

public interface IEntity { 
    double Id { get; set; } 
    string Number { get; set; } 
    string Firstname { get; set; } 
    string Surname { get; set; } 
    long PhoneNumber { get; set; } 
} 
public interface ICustomer : IEntity { 
} 
public interface ISupplier : IEntity { 
    string Term { get; set; } 
} 
public sealed Customer : ICustomer { 
    public Customer() { 
    } 
    public double Id { get; set; } 
    public string Number { get; set; } 
    public string Firstname { get; set; } 
    public string Surname { get; set; } 
    public long PhoneNumber { get; set; }  
} 
public sealed Supplier : ISupplier { 
    public Supplier() { 
    } 
    public double Id { get; set; } 
    public string Number { get; set; } 
    public string Firstname { get; set; } 
    public string Surname { get; set; } 
    public long PhoneNumber { get; set; }  
    public string Term { get; set; } 
} 

考慮到上面的代碼,你可以用你的用戶控件的DataSource屬性與IEntity綁定,所以你的財產可能會喜歡這樣。

[System.ComponentModel.DesignTimeVisible(true), System.ComponentModel.DesignerCategory("CustomerUserControl"), System.ComponentModel.Description("Sets the CustomerUserControl DataSource property")] 
public IList<IEntity> DataSource { 
    set { 
     _customerBindingSource.DataSource = value; 
    } 
} 

這就是說,如果你想進一步推進,你可能只是暴露,以便把它們設置在設計時你的用戶控件的數據綁定控件的屬性。考慮到這一點,您將需要將BindingSource公開爲公共屬性,以便您可以在設計時進行設置,然後從此BindinSource中選擇DataMember。

我希望這可以幫助你一點或至少,給你一些進一步搜索的軌道。

1

如果你想對所有自動做到這一點,你可以看看從你的用戶控件或類似的東西的加載事件父窗體綁定源...

Dim components As Reflection.FieldInfo = typ.GetField("components", Reflection.BindingFlags.DeclaredOnly Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic) 

Dim lstBindingSources As New List(Of BindingSource) 
For Each obj As Object In components.Components 
    Dim bindSource As BindingSource = TryCast(obj, BindingSource) 
    If bindSource IsNot Nothing Then 
     lstBindingSources.Add(bindSource) 
    End If 
Next 
If lstBindingSources.Count = 1 Then 
    MyBindingSource.DataSource = lstBindingSources(0).DataSource 
End If 
1

如果您分配相同的對象引用作爲兩個綁定資源上的數據源,則控件將不會在第二個綁定資源上一致地更新。可能的話,上面的選擇了妥協如下:

  1. 暫告一個的BindingSource添加到該用戶控件並使用VS設計師綁定設置控件。
  2. designer.vb帶入代碼編輯器。搜索由設計人員創建的所有"DataBindings.Add"行。全部複製到記事本。
  3. 從設計器中刪除綁定源並在代碼中添加綁定源引用。添加與設計器中使用的名稱相同的bindingsource屬性。在設定器爲屬性,粘貼記事本的所有行上述步驟2中
  4. 在窗體的Load事件,表單的BindingSource的分配給所述用戶控件的屬性。如果用戶控件嵌入到其他用戶控件中,則可以使用父控件的handlecreated事件來執行相同操作。

由於VS設計器正在創建所有這些文字屬性名稱,所以輸入較少且輸入錯誤較少。

1

我知道這是一個遲到的答案;但是,讀這篇文章的人可能會很有用。

我有一個UserControl是數據綁定控件。我需要在UserControl上有BindingSource,以便能夠在設計時綁定控件。然而,「真實」BindingSource位於Form。換句話說,UserControl上的控件應該表現得好像它們直接坐在表單上(或表單上的ContainerControl)。

這一解決方案背後的想法是看的DataSourceChanged事件的「真正的」 BindingSource並且當它改變其分配給DataSource當地BindingSource。爲了找到「真正的」 BindingSource我讓包含它實現以下接口的Form(或Control):

public interface IDataBound 
{ 
    BindingSource BindingSource { get; } 
} 

我們可以看爲ParentChanged事件,以便控制的,知道什麼時候已經添加它到FormContainerControl。這裏的問題是,這個ContainerControl本身可能還沒有被添加到Form(或另一個ContainerControl)中。在這種情況下,我們訂閱的最後家長的ParentChanged情況下,我們的父母鏈發現,等到這最後的父母已經添加的等等,直到我們找到一個ControlForm實施IDataBound。當找到IDataBound時,我們訂閱BindingSourceDataSourceChanged事件。

public partial class MyUserControl : UserControl 
{ 
    private IDataBound _dataBoundControl; 
    private Control _parent; 

    public MyUserControl() 
    { 
     InitializeComponent(); 
     if (LicenseManager.UsageMode == LicenseUsageMode.Runtime) { 
      _parent = this; 
      SearchBindingSource(); 
     } 
    } 

    private void SearchBindingSource() 
    { 
     if (_parent != null && _dataBoundControl == null) { 
      while (_parent.Parent != null) { 
       _parent = _parent.Parent; 
       _dataBoundControl = _parent as IDataBound; 
       if (_dataBoundControl != null) { 
        if (_dataBoundControl.BindingSource != null) { 
         _dataBoundControl.BindingSource.DataSourceChanged += 
          new EventHandler(DataBoundControl_DataSourceChanged); 
        } 
        return; 
       } 
      } 
      // This control or one of its parents has not yet been added to a 
      // container. Watch for its ParentChanged event. 
      _parent.ParentChanged += new EventHandler(Parent_ParentChanged); 
     } 
    } 

    void Parent_ParentChanged(object sender, EventArgs e) 
    { 
     SearchBindingSource(); 
    } 

    void DataBoundControl_DataSourceChanged(object sender, EventArgs e) 
    { 
     localBindingSource.DataSource = _dataBoundControl.BindingSource.DataSource; 
    } 
}