我一直在尝试创建一个小型表单应用程序,我想尝试将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继承的类?
答案 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; }
}
,最后将绑定源设置为网格的数据源。注意:制作MyClassRepository
和MyClassList
全局变量是不必要的,并且设置为检查myClassRepository
是否与用户在网格中执行的操作实时更新。这是在下面的按钮点击事件中完成的。
gridBindingSource
我希望这是有道理的。 ; - )
答案 1 :(得分:0)
Designer为设计时支持设置DataSource = typeof(Something)
,例如,允许您从下拉列表中选择DataMember
,或者让您在设置数据绑定时从下拉列表中选择数据源属性。
如何让Designers自动生成代码集
DataSource
到对象的实例?
强迫设计人员这样做没有多大意义,因为设计人员不知道您将用于加载数据的真实数据源是什么。它可以是Web服务,WCF服务,业务逻辑层类。
因此,在运行时,您需要将列表实例分配给DataSource
。例如,在表单的Load
事件中。