我一直在尝试创建一个小型表单应用程序,我想尝试将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背后的代码,看看发生了什么。setter调用ResetList
,它试图通过调用ListBindingHelper.GetListFromType
来创建dataSourceInstance
。这个调用最终调用SecurityUtils.SecureCreateInstance(Type)
,其中type是BindingList<MyClassRepository>
。这将null传递给args,args传递给Activator.CreateInstance
,Activator.CreateInstance
返回一个空集合。
这个方法调用了ListBindingHelper.GetList(dataSourceInstance, this.dataMember)
,它会为我的MyClassList
属性生成一个PropertyDescriptor
,并将其赋值给dmProp
。
此时,GetList
调用GetFirstItemByEnumerable(dataSource as IEnumerable)
,其中dataSource是之前创建的(空的)BindingList<MyClassRepository>
示例,并返回(currentItem == null) ? null : dmProp.GetValue(currentItem);
。
dmProp/MyClassList的值永远不会被访问,BindingSource也永远不会被我创建的示例填充。我做错了什么吗?如果没有,源代码中是否有bug?在我看来,要么应该调用SecureCreateInstance(Type type, object[] args)
,MyClassList应该通过args传递,而不是现有的SecureCreateInstance(Type type)
调用,要么应该使用dmProp
的值。
如果这是不正确的,我如何让设计器自动生成的代码将DataSource设置为对象的示例?或者我必须从BindingSource继承吗?如果是后者,为什么它给予你选择一个不从BindingSource继承的类的选项?
3条答案
按热度按时间gkl3eglg1#
正如Reza Aghaei所指出的,在设计器中,将
BindingSource.DataSource
设置为“MyClassRepository”可能会起作用,但是您仍然需要初始化(创建一个新的)MyClassRepository
对象。我在发布的代码中没有看到这行代码:MyClassRepository myRepositiory = new MyClassRepository();
数据源是空的,因为您还没有创建“MyClassRepository”的示例,正如Reza指出的那样,这通常以Load
事件的形式完成。为了保持简单,在设计器中删除
BindingSource
的DataSource
,并在表单加载事件中简单地设置BindingSource’s
数据源,如下所示。首先,创建MyClassRepository
的新“示例”,然后使用其MyClassList
属性作为BindingSource
的数据源。我希望这能有所帮助。字符串
编辑-
经过进一步的审查.我同意你应该能够做到你所描述的。我能够得到它的工作与预期的代码如下。
型
我在“设计器”中遵循了相同的步骤,它按预期工作。还有什么我错过了吗?正如你所说的.使用
MyClassRepository mcr = new MyClassRepository()
似乎是不必要的。此外,如果你不能使用上面的两种方法之一让它工作.编辑2
没有创建一个“新的”
MyClassRepository
,对象是意外的,我没有意识到添加到列表/网格的新项目将进入bindingSource1
。主要的一点是,没有示例化一个“新的”MyClassRepository
对象,构造函数将永远不会运行。这意味着属性List<MyClass> MyClassList
将永远不会被示例化。也不会设置默认值。因此,
MyClassList
变量在此上下文中将不可访问。例如,在此特定情况下,如果将行添加到网格中,那么bindingSource1.Count
属性将返回正确的行数。不仅MyClassList
中的行数为零(0),而且更重要的是. new”MyClassRepository
对象?由于这种不可访问性,MyClassList
将永远不会被使用。编辑3 -
你想要实现的可以通过无数种方式来实现。如果你想让
MyClassList
包含用户在网格中所做的真实的时间更改,那么使用你的代码和我发布的代码是行不通的。例如,在你的代码和我的代码中.如果用户向网格中添加了一行,它会将该项添加到“bindingSource”中,但不会将其添加到MyClassList
中。我只能猜测这不是您想要。否则,MyClassList
的用途是什么。下面的代码“将”按预期使用MyClassList
。如果你删除“设计器”透视图......你可以在三(3)中做同样的事情代码行.如果你修复损坏的MyClassRepository
类并在表单加载事件上创建一个新的类。恕我直言,这比摆弄设计器要容易得多。对
MyClassRepository
的更改.添加了一个构造函数,添加了一个size属性和一个方法作为示例。型
对
MyClass
的更改...添加了一个属性作为示例。型
最后,表单加载事件创建一个新的
MyClassRepository
,设置绑定源指向MyClassList
,最后将绑定源设置为网格的数据源。注意:使myClassRepository
和gridBindingSource
成为全局变量是不必要的,这样设置是为了检查MyClassList
是否随用户在网格中的操作而真实的更新。在下面的按钮单击事件中完成。型
我希望这是有意义的;-)
gmxoilav2#
设计工具会针对设计阶段支援设定
DataSource = typeof(Something)
,例如,让您在设定数据系结时,从下拉式清单中选择DataMember
,或从下拉式清单中选择数据来源属性。如何使设计器自动生成的代码将
DataSource
设置为对象的示例?强迫设计人员这样做没有多大意义,因为设计人员不知道您将使用什么样的真实的数据源来加载数据。它可以是Web服务、WCF服务或业务逻辑层类。
因此在运行时,需要将列表的一个示例赋给
DataSource
。例如,在表单的Load
事件中。o75abkj43#
基于此处的其他答案,Visual Studio设计器将创建一个
BindingSource
对象,并将其DataSource
属性设置为要绑定的对象的Type
。它这样做的原因是通知设计器哪些属性可用于绑定。设计器没有对象示例的概念,因为您的程序当时未运行。如果您遵循Microsoft的How to: Create a simple-bound control on a Windows Form,您可能会发现自己感到困惑,因为Form仍然看起来不像有任何绑定的属性。不幸的是,该指南特别缺乏,并且没有跟进代码以完成目标。作为程序员,您仍然有责任创建您想要绑定的对象的示例,然后执行任何代码,这些代码将导致对象填充最终将出现在绑定Form中的数据。
我认为,我们如何做到这一点,最好由Reza的answer来解释;在Form的类中创建一个
private
成员,该成员将保存要绑定的对象的示例。然后,您将使用Form的Load
事件示例化对象(或者如果示例是在代码中的其他地方创建的,则通过其他方式获取示例),将其分配给Form中的私有成员,然后 * 将BindingSource
的.DataSource
属性设置为新的私有对象示例 *。这是我和我认为许多其他人错过的关键步骤,Microsoft可以更好地记录这一点。例如,看看他们的BindingSource class文档。字符串
您唯一需要担心的部分是
binding1.DataSource
行;这是您指定支持对象作为数据源的地方。