将DataSource与Windows窗体中的对象一起使用

时间:2018-04-13 20:52:19

标签: c# .net winforms datagridview bindingsource

我一直在尝试创建一个小型表单应用程序,我想尝试将DataGridView直接绑定到一个对象集合。

我创建了以下类

public class MyClassRepository
{
    public List<MyClass> MyClassList { get; set; } = new List<MyClass> { new MyClass { Name = "Test" } };
}

public class MyClass
{
    public string Name { get; set; }
}

我将以下代码添加到要测试的表单中。在通过UI设置BindingSource之后,我根据设计器中的代码进行了此操作(同时遵循此步骤https://msdn.microsoft.com/en-us/library/ms171892.aspx

var tmp = new BindingSource();
tmp.DataMember = "MyClassList";
tmp.DataSource = typeof(MyClassRepository);

当这项工作没有成功时,我开始浏览BindingSource背后的代码,看看发生了什么。设置者调用ResetList,通过调用dataSourceInstance来尝试创建ListBindingHelper.GetListFromType。此调用最终会调用SecurityUtils.SecureCreateInstance(Type),其中type为BindingList<MyClassRepository>。这将null传递给传递Activator.CreateInstance的args,返回一个空集合。

调用此ListBindingHelper.GetList(dataSourceInstance, this.dataMember)之后。此方法调用ListBindingHelper.GetListItemProperties,这会为PropertyDescriptor属性生成MyClassList,并将其分配给dmProp

此时GetList调用GetFirstItemByEnumerable(dataSource as IEnumerable),其中dataSource是先前创建的(和空)BindingList<MyClassRepository>实例,并返回(currentItem == null) ? null : dmProp.GetValue(currentItem);

永远不会访问dmProp / MyClassList的值,并且永远不会使用我创建的实例填充BindingSource。难道我做错了什么?如果不是源代码中有错误?在我看来应该调用SecureCreateInstance(Type type, object[] args)和MyClassList应该通过args而不是现有的SecureCreateInstance(Type type)调用传递,或者dmProp的值应该被使用?

如果这不正确,如何让设计师自动生成代码将DataSource设置为对象的实例?或者我必须从BindingSource继承?如果后者为什么它会让你选择一个不从BindingSource继承的类?

2 个答案:

答案 0 :(得分:1)

正如Reza Aghaei指出的那样,在设计器中,将BindingSource.DataSource设置为“MyClassRepository”可能有效,但是您仍然需要初始化(创建一个新的)MyClassRepository对象。我在发布的代码中的任何地方都没有看到这行代码:MyClassRepository myRepositiory = new MyClassRepository();数据源为空,因为您尚未创建“MyClassRepository”实例,而Reza指出,这通常以[{{{ 1}}事件。

为了简单起见,请删除设计器中Load的{​​{1}},然后在表单加载事件中设置DataSource数据源,如下所示。首先,创建BindingSource的新“实例”,然后使用其BindingSource’s属性作为MyClassRepository的数据源。我希望这会有所帮助。

MyClassList

修改-----

经过进一步审核......我同意您应该按照您的描述进行操作。我能够按照预期的方式使用下面的代码。

BindingSource

我在“设计师”中执行了相同的步骤,它按预期工作。还有其他我想念的东西吗?如你所说......使用MyClassRepository repOfMyClass; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { repOfMyClass = new MyClassRepository(); bindingSource1.DataSource = repOfMyClass.MyClassList; dataGridView1.DataSource = bindingSource1; } 似乎是不必要的。另外,如果你不能使用上述两种方法之一让它工作......那么还有其他的事情正在发生。如果它不能如上所述,会发生什么?

修改2

在没有创建“新”BindingSource bindingSource1; private void Form1_Load(object sender, EventArgs e) { bindingSource1 = new BindingSource(); bindingSource1.DataSource = typeof(MyClassRepository); bindingSource1.DataMember = "MyClassList"; dataGridView1.DataSource = bindingSource1; } 的情况下,对象出乎意料,我没有意识到添加到列表/网格中的新项目会进入MyClassRepository mcr = new MyClassRepository()。重点是,如果不实例化“新”MyClassRepository对象,构造函数将永远不会运行。这意味着属性bindingSource1永远不会被实例化。也不会设置默认值。

因此,MyClassRepository变量在此上下文中将无法访问。在此特定情况下的示例,如果将行添加到网格中,则List<MyClass> MyClassList属性将返回正确的行数。行计数不仅在MyClassList中为零(0),而且更重要的是......在没有首先实例化“新”bindingSource1.Count对象的情况下,您甚至会“访问”MyClassList属性?由于无法访问,MyClassList永远不会被使用。

编辑3 ---

您想要实现的目标可以通过多种方式完成。如果您希望MyClassRepository包含用户在网格中所做的实时更改,则使用您的代码和我发布的代码将不起作用。例如,在您的代码和我的代码中...如果用户向网格添加一行,它会将该项添加到“bindingSource”,但不会将其添加到MyClassList。我只能猜测这不是你想要的。否则,MyClassList的目的是什么。下面的代码“将”按预期使用MyClassList。如果你删除“设计者”视角......你可以在三(3)行代码中做同样的事情......如果你修复了损坏的MyClassList类并在表单加载事件上创建了一个新类。恕我直言,这比摆弄设计师容易得多。

MyClassList的更改...添加了构造函数,添加了size属性和方法作为示例。

MyClassRepository

MyClassRepository的更改...添加了一个属性作为示例。

class MyClassRepository {

  public List<MyClass> MyClassList { get; set; }
  public int MaxSize { get; set; }

  public MyClassRepository() {
    MyClassList = new List<MyClass>();
    MaxSize = 1000;
  }

  public void MyClassListSize() {
    MessageBox.Show("MyClassList.Count: " + MyClassList.Count);
  }

  // other list manager methods....

}

最后,用于创建新MyClass的表单加载事件,将绑定源设置为指向class MyClass { public string Name { get; set; } public string Age { get; set; } } ,最后将绑定源设置为网格的数据源。注意:制作MyClassRepositoryMyClassList全局变量是不必要的,并且设置为检查myClassRepository是否与用户在网格中执行的操作实时更新。这是在下面的按钮点击事件中完成的。

gridBindingSource

我希望这是有道理的。 ; - )

答案 1 :(得分:0)

Designer为设计时支持设置DataSource = typeof(Something),例如,允许您从下拉列表中选择DataMember,或者让您在设置数据绑定时从下拉列表中选择数据源属性。

  

如何让Designers自动生成代码集   DataSource到对象的实例?

强迫设计人员这样做没有多大意义,因为设计人员不知道您将用于加载数据的真实数据源是什么。它可以是Web服务,WCF服务,业务逻辑层类。

因此,在运行时,您需要将列表实例分配给DataSource。例如,在表单的Load事件中。