问题
I have a GUI which allows the user to select a report to view/edit. When the user selects a report, it shows the Items in the report. The Item has many properties - most of which are binding properly. One of the properties is Owner, and this is bound to a ComboBoxColumn.
- Report
- Items
- Owner
- Items
I have done something very similar to this a few times and had no problems when I set the DataPropertyName
, DataSource
, ValueMember
, and DisplayMember
. The only difference is that this time instead of the Item
type having an OwnderID
it actually has an instance of the Owner
object.
I saw a suggestion on another post to solve this issue by giving the items bound in the list a self-referencing property that allows them to return themselves for the purposes of setting the ValueMember
However, When I bind it this way:
OwnerColumn.DataPropertyName = "Owner"
OwnerColumn.DataSource = ownersBindingSource1
OwnerColumn.ValueMember = "Self"
OwnerColumn.DisplayMember = "OwnerName"
I get a lot of errors like:
Unable to cast object of type 'System.String' to type 'Owner'.
and:
The following exception occurred in the DataGridView:
System.ArgumentException: DataGridViewComboBoxCell value is not valid.
To replace this default dialog please handle the DataError event.
I was able to get around some of these errors by binding it like this:
OwnerColumn.DataPropertyName = "Owner"
OwnerColumn.DataSource = ownersBindingSource1
and also by making the ToString
function on the Owner
display the OwnerName
property. This seems pretty hacky though - and I think I'm misunderstanding something fundamental as it still does not function properly. Any help would be much appreciated.
回答1:
I found out that a lot of my errors were coming from my misunderstanding of various articles I had read, as well as sloppy code.
I neglected to specify the return type on a few of the properties, option explicit / option strict were both off, and there had been some corruption in my designer and a few of the columns were duplicated.
A solution to this that I liked the most was: http://code.google.com/p/systembusinessobjects/source/browse/trunk/System.BusinessObjects.Framework/Data/SafeBindingLists.cs . Unfortunately, this requires Castle proxy, and an older version of NHibernate.
Here is the simple solution that I found:
The issue is that you cannot bind a list with objects of multiple types. The goal is to be able to have the ComboBox directly set the value of a property on the object it is bound to with another object.
I chose to use a View object, and bind the list to that.
View Object:
Public Class OwnerView
Private _owner As Owner
Public ReadOnly Property OwnerId As Integer
Get
Return _owner.OwnerId
End Get
End Property
Public ReadOnly Property OwnerName As String
Get
Return _owner.OwnerName
End Get
End Property
Public ReadOnly Property OwnerAbbreviation As String
Get
Return _owner.OwnerAbbreviation
End Get
End Property
Public Overridable ReadOnly Property Self As Owner
Get
Return _owner
End Get
End Property
Public Sub New(ByVal owner As Owner)
_owner = owner
End Sub
End Class
Binding:
With OwnerColumn
.SortMode = DataGridViewColumnSortMode.Automatic
.ReadOnly = False
.Name = "OwnerColumn"
.HeaderText = "Owner"
Dim bs As New BindingSource()
For Each co As Owner In Owners
bs.Add(New OwnerView(co))
Next
.DataPropertyName = "Owner"
.DataSource = bs
.ValueMember = "Self"
.DisplayMember = "OwnerName"
ItemDataGridView.Columns.Add(OwnerColumn)
End With
来源:https://stackoverflow.com/questions/8981648/binding-a-collection-of-objects-to-a-comboboxcolumn-in-a-datagridview