在UserControl中使用BindingSource

时间:2009-06-11 17:09:21

标签: winforms user-controls bindingsource

我有一个UserControl,包含多个字段,我想绑定到BindingSource。我还希望UserControl公开一些BindingSource属性,以便它可以放在Form上并绑定到表单上的BindingSource。是否有捷径可寻?我意识到我可以在其BindSource setter中重新绑定UserControl的所有控件。但这似乎是错误的。是否有一些BindingSource代理可以让我将用户控件中的BindingSource链接到表单中的BindingSource?

4 个答案:

答案 0 :(得分:5)

根据你的问题,我很难得到你打算做的事情。因此,我会尽力为您提供有关此事的有趣信息。

首先,让我们考虑一下客户管理软件项目中的以下UserControl。

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属性来获得尽可能最抽象的,那么你将不得不编写一个方法来检测类型传递对象,然后相应地绑定属性。也许你可以去的一个很好的方法就是反思,如果你觉得它很舒服的话。以任何可能的方式,您可以想象使用这种多态性功能,您必须自己编写一个所有可绑定对象必须实现的接口。这样,您将避免使用未知的属性名称,何时将绑定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; }
}

考虑到上面的代码,您可以使用UserControl的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;
    }
}

也就是说,如果你想进一步推动,你可以公开你的UserControl的控件DataBindings属性,以便在设计时设置它们。考虑到这一点,您将希望将BindingSource公开为公共属性,以便您也可以在设计时将其设置,然后从此BindinSource中选择您的DataMember。

我希望这对您有所帮助或至少为您提供一些进一步搜索的记录。

答案 1 :(得分:1)

如果您想自动执行此操作,您可以在用户控件的load事件中查找父表单中的绑定源或类似的内容......

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

答案 2 :(得分:1)

如果在两个bindingsources上为同一个对象引用分配相同的对象引用,则控件将不会在第二个bindingsource上一致地更新。可能,对上述选择的妥协如下:

  1. 暂时将bindingsource添加到usercontrol并使用VS设计器设置对控件的绑定。
  2. designer.vb带到代码编辑器中。搜索设计器创建的所有"DataBindings.Add"行。将它们全部复制到记事本中。
  3. 从设计器中删除bindingsource并在代码中添加bindingsource引用。为bindingsource添加一个属性,其名称与设计器中使用的属性相同。在属性的setter中,在步骤2中粘贴上面记事本中的所有行。
  4. 在表单的Load事件中,将表单的bindingsource分配给用户控件上的属性。如果用户控件嵌入在另一个用户控件中,则可以使用父控件的handlecreated事件来执行相同操作。
  5. 打字少,拼写错误少,因为VS设计师正在创建所有这些文字文字属性名称。

答案 3 :(得分:1)

我知道这是一个迟到的答案;但是,阅读这篇文章的其他人可能会有所帮助。

我对UserControl的数据绑定控件。我需要在BindingSource上设置UserControl才能在设计时绑定控件。 &#34;真实&#34;但是,BindingSource位于Form。换句话说,UserControl上的控件应该就像直接坐在表单上一样(或在表单上的ContainerControl上)。

这个解决方案背后的想法是观察&#34;真实&#34;的DataSourceChanged事件。 BindingSource并在其发生变化时将DataSource分配给本地BindingSource。为了找到真实的&#34; BindingSource我让包含它的Form(或Control)实现以下界面:

public interface IDataBound
{
    BindingSource BindingSource { get; }
}

我们可以查看控件的ParentChanged事件,以了解控件何时添加到FormContainerControl。这里的问题是,此ContainerControl本身可能尚未添加到Form(或其他ContainerControl)。在这种情况下,我们订阅我们在父链中找到的最后一个父项的ParentChanged事件,并等到最后一个父项被添加,依此类推,直到我们找到Control或{{1实施Form。找到IDataBound后,我们会订阅其IDataBound的{​​{1}}事件。

DataSourceChanged