Groups | Blog | Home
all groups > dotnet windows forms databinding > may 2007 >

dotnet windows forms databinding : DataGridView won't bind to IList(Of T) implementation.


tendim
5/18/2007 11:17:25 AM
I've been trying to gea DataGridView to bind to an IList(Of T)
implementation. Basically, I have a fixed size list where the members
can be changed, but new members can not leave and old members cannot
be deleted.

To isolate the problem I made a simple project with a simple class
which implements IList(Of T). The implementation raises
NotSupportedException for anything that would not be supported
(Adding,deleting, clear, insert at, etc.). I'm 100% positive that the
problem lies in my IList(Of T) implementation, but I don't know what I
am doing wrong. I say "100%" because if I expose the list which is
stored internally, that exposed list populates the DGV just fine.

So, on my form I have a DataGridView (topMyDGVMyData) and a single
button. When the button is pressed, the following code is executed:

'Code
Start____________________________________________________________________

Private Sub topButtonFill_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles topButtonFill.Click
Me.topDGVMyData.AutoGenerateColumns = False
Me.topDGVMyData.AutoSize = True
Me.topDGVMyData.DataSource = oMySource.ExposedList

Me.topDGVMyData.Columns.Clear()

Dim oCol As DataGridViewColumn = Nothing

oCol = New DataGridViewTextBoxColumn
oCol.DataPropertyName = "DatumName"
oCol.Name = "The Name"
Me.topDGVMyData.Columns.Add(oCol)

oCol = New DataGridViewTextBoxColumn
oCol.DataPropertyName = "DatumValue"
oCol.Name = "The Value"
Me.topDGVMyData.Columns.Add(oCol)
End Sub

'Code
End______________________________________________________________________

And of course, I have my simple classes:

'Code
Start____________________________________________________________________

'Simple datum for MyBindingSource with a readonly property and a
'readwrite property.
Public Class MyDatum
Implements IComparable(Of MyDatum)

Implements IEquatable(Of MyDatum)

Private _strName As String
Private _dblValue As Double

Public Sub New(ByVal p_strName As String, ByVal p_dblValue As
Double)
_strName = p_strName
_dblValue = p_dblValue
End Sub

Private Sub New()

End Sub

Public ReadOnly Property DatumName() As String
Get
Return _strName
End Get

End Property

Public Property DatumValue() As Double
Get
Return _dblValue
End Get
Set(ByVal value As Double)
_dblValue = value
End Set
End Property

Public Overrides Function Equals(ByVal obj As Object) As Boolean
If TypeOf obj Is MyDatum Then
Return Me.Equals(CType(obj, MyDatum))
Else
Return False
End If
End Function

Public Overloads Function Equals(ByVal other As MyDatum) As
Boolean Implements System.IEquatable(Of MyDatum).Equals
Return Me.DatumName = other.DatumName And Me.DatumValue =
other.DatumValue
End Function

Public Overloads Function CompareTo(ByVal other As MyDatum) As
Integer Implements System.IComparable(Of MyDatum).CompareTo
If Me.DatumName.CompareTo(other.DatumName) = 0 Then
Return Me.DatumValue.CompareTo(other.DatumValue)
Else
Return Me.DatumName.CompareTo(other.DatumName)
End If
End Function

Public Overrides Function ToString() As String
Return Me.DatumName & ": " & Me.DatumValue
End Function
End Class

'This implements IList(Of MyDatum) and acts as a fixed-size list.
'Implementation really just wraps around an internally stored list
'(exposed by Me.ExposedList).
Public Class MyBindingSource
Implements IList(Of MyDatum)

Private _oList As List(Of MyDatum)

Public ReadOnly Property ExposedList() As List(Of MyDatum)
Get
Return _oList
End Get
End Property

Public Sub New()
Dim i As Integer = 0

_oList = New List(Of MyDatum)

For i = 0 To 10
_oList.Add(New MyDatum("Value #" & i, i))
Next
End Sub

Public Sub Add(ByVal item As MyDatum) Implements
System.Collections.Generic.ICollection(Of MyDatum).Add
Throw New NotSupportedException
End Sub

Public Sub Clear() Implements
System.Collections.Generic.ICollection(Of MyDatum).Clear
Throw New NotSupportedException
End Sub

Public Function Contains(ByVal item As MyDatum) As Boolean
Implements System.Collections.Generic.ICollection(Of MyDatum).Contains
Return _oList.Contains(item)
End Function

Public Sub CopyTo(ByVal array() As MyDatum, ByVal arrayIndex As
Integer) Implements System.Collections.Generic.ICollection(Of
MyDatum).CopyTo
_oList.CopyTo(array, arrayIndex)
End Sub

Public ReadOnly Property Count() As Integer Implements
System.Collections.Generic.ICollection(Of MyDatum).Count
Get
Return _oList.Count
End Get
End Property

Public ReadOnly Property IsReadOnly() As Boolean Implements
System.Collections.Generic.ICollection(Of MyDatum).IsReadOnly
Get
Return False
End Get
End Property

Public Function Remove(ByVal item As MyDatum) As Boolean
Implements System.Collections.Generic.ICollection(Of MyDatum).Remove
Throw New NotSupportedException
End Function

Public Function GetEnumerator() As
System.Collections.Generic.IEnumerator(Of MyDatum) Implements
System.Collections.Generic.IEnumerable(Of MyDatum).GetEnumerator
Return _oList.GetEnumerator
End Function

Public Function IndexOf(ByVal item As MyDatum) As Integer
Implements System.Collections.Generic.IList(Of MyDatum).IndexOf
Return _oList.IndexOf(item)
End Function

Public Sub Insert(ByVal index As Integer, ByVal item As MyDatum)
Implements System.Collections.Generic.IList(Of MyDatum).Insert
Throw New NotSupportedException
End Sub

Default Public Property Item(ByVal index As Integer) As MyDatum
Implements System.Collections.Generic.IList(Of MyDatum).Item
Get
Return _oList.Item(index)
End Get
Set(ByVal value As MyDatum)
_oList.Item(index) = value
End Set
End Property

Public Sub RemoveAt(ByVal index As Integer) Implements
System.Collections.Generic.IList(Of MyDatum).RemoveAt
Throw New NotSupportedException
End Sub

Public Function GetEnumerator1() As System.Collections.IEnumerator
Implements System.Collections.IEnumerable.GetEnumerator
Return _oList.GetEnumerator
End Function
End Class

'Code
End______________________________________________________________________

As you can see from my MyDatum class, the DatumName property is read
tendim
5/18/2007 11:23:26 AM
I forgot to mention that the posted code above "works":

This is populating the DGV with the exposed list:
[quoted text, click to view]

But the following code doesn't work:
[quoted text, click to view]

Even though oMySource implements IList(Of T) and that should work with
a DGV.
RobinS
5/20/2007 9:53:00 AM
You might try using an IBIndingList(of T) instead. That list is designed to
be databound to controls.

Robin S.
------------------------------
[quoted text, click to view]

tendim
5/20/2007 11:30:05 AM
[quoted text, click to view]

I considered that, but since using a regular List(Of T) works, I'd
like to isolate what is wrong with my implementation of IList(Of t)
(which should provide identical functionality to List(Of T)). If
there is something wrong with my implementation I'd rather nail it
down now, than pull hairs out trying to find the bug later. :)

Marc Gravell
5/28/2007 3:41:28 PM
[quoted text, click to view]

Very simple; data-binding doesn't use then generic IList(Of t) =
IList<T> interface; rather, it uses the non-generic IList interface
(or an IListSource which itself returns an IList). Your implementation
should include this (presumably explicit, since you want your generic
version to take precedence).

So simply implement IList and all should be fine. For full binding
support, you may also wish to consider:
IBindingList
IBindingListView
ICancelAddNew
IRaiseItemChangedEvents
ITypedList (although this isn't normally needed if your list has a
typed public indexer SomeType this[int], where SomeType will be used
to infer the properties)

Marc
AddThis Social Bookmark Button