简体   繁体   English

WinForms数据绑定和外键关系

[英]WinForms databinding and foreign key relationships

I'm developing a WinForms application (.Net 3.5, no WPF) where I want to be able to display foreign key lookups in a databound DataGridView. 我正在开发一个WinForms应用程序(.Net 3.5,没有WPF),我希望能够在数据绑定DataGridView中显示外键查找。

An example of the sort of relationship is that I have a table of OrderLines. 这种关系的一个例子是我有一个OrderLines表。 Orderlines have a foreign key relationship to Products and Products in turn have a foreign key relationship to ProductTypes. 订单行与产品和产品具有外键关系,而产品和产品又与ProductTypes具有外键关系。

I'd like to have a databound DataGridView where each row represents an orderline, displaying the line's product and producttype. 我想要一个数据绑定DataGridView,其中每一行代表一个订单行,显示该行的产品和产品类型。

Users can add or edit orderlines direct to the grid and choose the product for the order line from a comboBoxColumn - this should then update the producttype column, showing the producttype for the selected product, in the same row. 用户可以直接向网格添加或编辑订单行,并从comboBoxColumn中为订单行选择产品 - 然后应该在同一行中更新producttype列,显示所选产品的产品类型。

The closest to a good fit that I've found so far is to introduce a domain object representing an orderline then bind the DataGridView to a collection of these orderlines. 到目前为止,我发现的最接近的一个很好的拟合是引入一个表示订单行的域对象,然后将DataGridView绑定到这些订单行的集合。 I then add properties to the orderline object that expose the product and the producttype, and raise relevant notifypropertychanged events to keep everything up to date. 然后,我将属性添加到公开产品和产品类型的订单行对象,并引发相关的notifypropertychanged事件以使所有内容保持最新。 In my orderline repository I can then wire up the mappings between this orderline object and the three tables in my database. 在我的订单行存储库中,我可以将此订单行对象与数据库中的三个表之间的映射连接起来。

This works for the databinding side of things, but having to hand code all that OR-mapping in the repository seems bad. 这适用于数据绑定方面,但必须手动编写存储库中所有OR映射的代码似乎很糟糕。 I thought nHibernate would be able to help with this wiring up but am struggling with the mappings through all the foreign keys - they seem to work ok (the foreignkey lookup for an orderline's product creates the correct product object based on the foreign key) until I try to do the databinding, I can't get the databound id columns to update my product or producttype objects. 我认为nHibernate能够帮助完成这个连接但是我正在努力通过所有外键的映射 - 它们似乎工作正常(外键查找订单行的产品根据外键创建正确的产品对象)直到我尝试进行数据绑定,我无法获取数据绑定id列来更新我的产品或producttype对象。

Is my general approach even in the right ballpark? 我的一般方法是否在正确的球场? If it is, what is a good solution to the mapping problem? 如果是,那么映射问题的解决方案是什么?

Or, is there a better solution to databinding rows including foreign key lookups that I haven't even considered? 或者,是否有更好的数据绑定行解决方案,包括我甚至没有考虑过的外键查找?

I think the problem you're having is that when you are binding to a grid, it is not enough to support INotifyPropertyChanged, but you have to fire the ListChanged events in your IBindingList implementation and make sure that you override and return true for the SupportsChangeNotification property. 我认为您遇到的问题是,当您绑定到网格时,仅支持INotifyPropertyChanged是不够的,但您必须在IBindingList实现中触发ListChanged事件并确保覆盖并为SupportsChangeNotification返回true属性。 If you don't return true for this, the grid won't look for it to know if the data has changed. 如果您没有为此返回true,则网格不会查找它以了解数据是否已更改。

In .NET 2.0+, you can create a generic collection using the BindingList class, this will take care of most of the nastiness (just don't forget to override and return true for the SupportsChangeNotification property). 在.NET 2.0+中,您可以使用BindingList类创建一个泛型集合,这将处理大部分的恶意(只是不要忘记覆盖并为SupportsChangeNotification属性返回true)。

If the class you use for data binding has a property that is a collection (such as IBindingList or BindingList), then you can bind the foreign key grid to that property directly. 如果用于数据绑定的类具有属性是集合(例如IBindingList或BindingList),则可以直接将外键网格绑定到该属性。 When you configure the bindings in the Forms designer, just select the collection property as the data source for the grid. 在Forms设计器中配置绑定时,只需选择集合属性作为网格的数据源。 It should "just work". 它应该“正常工作”。 The only sneaky part is making sure that you handle empty or null collections the right way. 唯一鬼鬼祟祟的部分是确保以正确的方式处理空集合或空集合。

welcome to StackOverflow :) 欢迎来到StackOverflow :)

Normally what you would do is base the information in the drop down on two values ValueMember and DisplayMember . 通常,您要做的是将信息基于ValueMember和DisplayMember这两个值的下拉列表。

The ValueMember is the source of the actual controls value (this will be the key value in the order line), the display member is the value that is displayed to the user instead of the value (this will be the FK value). ValueMember是实际控件值的来源(这将是订单行中的键值),显示成员是显示给用户的值而不是值(这将是FK值)。

Is there no particular reason you cannot just return all the data required and set these properties? 没有特别的理由你不能只返回所需的所有数据并设置这些属性吗?

Well, I don't know whether it's supported by the DataGridView, but when you're doing regular WinForms databinding (say, to a regular TextBox) you can use property paths to navigate through object relationships. 好吧,我不知道DataGridView是否支持它,但是当您正在进行常规WinForms数据绑定(比如说,对常规TextBox)时,您可以使用属性路径来浏览对象关系。

Something like this: 像这样的东西:

myTextBox.DataBindings.Add("Text", anOrderLine, "OrderedPart.PartNumber");

Would be worth seeing if this works in your situation too. 值得一看的是,这是否适用于您的情况。

Here's a good "How Do I" video that demonstrates data binding: 这是一个很好的“我如何”视频,演示数据绑定:

http://windowsclient.net/learn/video.aspx?v=52579 http://windowsclient.net/learn/video.aspx?v=52579

My original question obviously wasn't clear, sorry about that. 我原来的问题显然不清楚,抱歉。

The problem wasn't with databinding to a DataGridView in general, or with the implementation of a DataGridViewComboBoxColumn - as the people who have answered already rightly say, that is well documented on the web. 问题不在于数据绑定到一般的DataGridView,或者与DataGridViewComboBoxColumn的实现有关 - 正如已经回答的人已经正确地说,在网络上有详细记录。

The problem I've been trying to solve is with the refresh of properties that are drilling down through relationships. 我一直试图解决的问题是刷新通过关系钻取的属性。

In my orders example, when I change the value of the "Product" column, the "Product Type" column is not being updated - even though in the code I am setting the property and firing the NotifyPropertyChanged event. 在我的订单示例中,当我更改“Product”列的值时,“Product Type”列未更新 - 即使在代码中我正在设置属性并触发NotifyPropertyChanged事件。 (In debug I go to all the right places) (在调试中我去了所有正确的地方)

After a lot of poking around I realised that this was not even working when I directly set the "Product Type" property of datasource, rather that setting it in the "Product" setter. 经过大量的讨论后,我意识到当我直接设置数据源的“产品类型”属性时,这甚至不起作用,而是在“产品”设置器中设置它。

The other thing that I believe has me back on the right track is that when I provide a mocked dataccess layer, created in the main form, everything works fine. 我认为让我回到正轨的另一件事是,当我提供一个模拟的数据访问层,在主窗体中创建时,一切正常。

Also, when I copy the IList made by nHibernate to a IBindingList - everything again appears fine. 此外,当我将nHibernate制作的IList复制到IBindingList时 - 一切看起来都很好。

So the problem is I think with threading and the NotifyPropertyChanged events being lost when using certain datasources, in certain ways (wish I could be more definitive than that!) 所以问题是我认为线程和NotifyPropertyChanged事件在使用某些数据源时会以某种方式丢失(希望我能比这更明确!)

I'm going to keep researching better ways of resolving this than copying the IList to the IBindingList - maybe I need to learn about thread marshalling. 我将继续研究解决此问题的更好方法,而不是将IList复制到IBindingList - 也许我需要了解线程编组。

Edit 编辑

I've now developed a solution that solves the issue and think I understand what was confusing me - it appears that anything but basic property databinding doesn't play nicely for lists that aren't derived from BindingList - as soon as I was trying to databind to properties that fired chained NotifyPropertyChanged events, things went haywire and my events got lost. 我现在已经开发出一个解决这个问题的解决方案,并且我认为我理解了令我困惑的事情 - 似乎除了基本属性数据绑定以外的任何东西都不能很好地用于不是从BindingList派生的列表 - 只要我试图数据绑定到触发链式NotifyPropertyChanged事件的属性,事情变得混乱,我的事件丢失了。

The data access solution I have now is using a variation of the Rob Conery IRepository pattern, returning my collections to be bound as a custom class I made, a SortableBindingLazyList that derives from BindingList, implements the Sort Core methods and also stores its internal list as a query, delaying the list materialisation. 我现在使用的数据访问解决方案是使用Rob Conery IRepository模式的变体,返回我的集合作为我自己创建的自定义类,从BindingList派生的SortableBindingLazyList,实现Sort Core方法并将其内部列表存储为查询,延迟列表实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM