01.Blogs :
Dennes  
O .NET no Rio de Janeiro, as atividades do grupo celulasRio, grupo formado pelos lideres do devASPNet e outras celulas acadêmicas do Rio

Problemas com databinding e Ilist em windows forms - solução


Ufa ! Essa deu trabalho, mas acabei descobrindo como resolver.

Me assustei por não encontrar exemplos ou referências sobre isso na internet, já que me pareceu um cenário até comum. Caso alguem já tenha passado por algo parecido, gostaria de algum comentário.

Cenário :
Uma combobox em windows form vinculada com um arrayList de itens para a exibição da lista e vinculada a uma origem de dados para gravação/leitura do item selecionado.

Os itens dentro do ArrayList precisam ser uma classe personalizada, para desta forma podermos ter o conjunto Texto/Valor e podermos ter o controle do formato de exibição dos itens na lista. Veja como fica essa classe personalizada a ser inserida dentro de um arrayList :

Public Class ItemLista
    
Dim vTexto As String
     Dim vValor As String

     Public Sub New(ByVal Texto As String, ByVal Valor As String
           vTexto = Texto
           vValor = Valor
     End Sub

     Public Property Texto() As String
         Get
            Return (vTexto)
         End Get
         Set(ByVal Value As String)
               vTexto = Value
         End Set
     End Property

     Public Property Value() As String
           Get
              Return (vValor)
           End Get
           Set(ByVal Value As String)
                   vValor = Value
           End Set
     End Property

     Public Function formatado() As String
             Return (ToString())
     End Function

     Public Overrides Function toString() As String
             Return (Value & " - " & Texto)
     End Function

End Class


Vejam então o código de vinculo de uma combo :

Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim obj As New ArrayList
        obj.Add(
New ItemLista("teste", 1))
        obj.Add(
New ItemLista("teste 2", 2))
        obj.Add(
New ItemLista("teste 3", 3))

        ComboBox1.DisplayMember = "formato"
        ComboBox1.ValueMember = "Value"
        ComboBox1.DataSource = obj
End Sub

E a tentativa de vínculo desta combo com uma origem de dados :

combobox1.databindings.add("SelectedValue", dados.Tables(0), "CampoValorSelecionado")

Problema : Simplesmente não funciona. A combo não consegue exibir o valor do item que está no banco nem gravar corretamente o valor selecionado.

Documentação na internet : Segundo as documentações que localizei na internet, qualquer classe que implemente a interface IList pode ser vinculada a um objeto visual, tal como uma combobox. Conforme identifiquei com o exemplo acima, é apenas parcialmente verdade, pois funciona com limitações.

Limitações : Demorei algum tempo até descobrir, e finalmente veio-me a luz! :-) Veja esse código adicional, inserido em um botão :

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

       ComboBox1.SelectedValue = 3

End Sub

Esse código não funciona quando a combobox está vinculada em um arrayList. Isso faz com que a combo vinculada em um arrayList não possa ter o selectedValue vinculado a um dataSet, pois não consegue fazer atribuições ao selectedValue.


Solução : Tentei com uma classe personalizada herdando de collectionBase, em vão. Até que finalmente fiz o óbvio : Comparar uma classe vinculável, como a dataView, com uma classe com esse problema, como o Arraylist, usando o object browser do visual studio. Bingo !

A classe dataView implementa a interface IBindingList, enquanto o arrayList não implementa essa interface. Essa é justamente a característica que causa essa diferença/problema.

Desta forma, apesar de ser dito que podemos fazer dataBinding com qualquer classe que implemente IList, só temos as funcionalidades completas se implementarmos IBindingList.

Criei uma classe personalizada implementando IBindingList. Muitos métodos da IBindingList podem ser implementados de forma dummy, ou seja, sem que realmente façam coisa alguma. O método mais importante, necessário para o processo de binding com a comboBox, é o método Find.

Veja mais abaixo como fica a classe implementando a IBindingList .

Uma das possibilidades para o fato destas características não terem sido notadas é que é possível criar uma dataTable e usa-la para substituir o ArrayList.

Public Class colecao

Implements System.ComponentModel.IBindingList

Dim obj As New ArrayList

Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer) Implements System.Collections.ICollection.CopyTo

obj.CopyTo(array, index)

End Sub

Public ReadOnly Property Count() As Integer Implements System.Collections.ICollection.Count

Get

Return (obj.Count)

End Get

End Property

Public ReadOnly Property IsSynchronized() As Boolean Implements System.Collections.ICollection.IsSynchronized

Get

Return (obj.IsSynchronized)

End Get

End Property

 

Public ReadOnly Property SyncRoot() As Object Implements System.Collections.ICollection.SyncRoot

Get

Return (obj.SyncRoot)

End Get

End Property

Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator

Return (obj.GetEnumerator)

End Function

Public Function Add(ByVal value As Object) As Integer Implements System.Collections.IList.Add

obj.Add(value)

Return (obj.Count - 1)

End Function

Public Sub Clear() Implements System.Collections.IList.Clear

obj.Clear()

End Sub

Public Function Contains(ByVal value As Object) As Boolean Implements System.Collections.IList.Contains

Return (obj.Contains(value))

End Function

Public Function IndexOf(ByVal value As Object) As Integer Implements System.Collections.IList.IndexOf

Return (obj.IndexOf(value))

End Function

 

Public Sub Insert(ByVal index As Integer, ByVal value As Object) Implements System.Collections.IList.Insert

obj.Insert(index, value)

End Sub

Public ReadOnly Property IsFixedSize() As Boolean Implements System.Collections.IList.IsFixedSize

Get

Return (obj.IsFixedSize)

End Get

End Property

 

Public ReadOnly Property IsReadOnly() As Boolean Implements System.Collections.IList.IsReadOnly

Get

Return (obj.IsReadOnly)

End Get

End Property

Default Public Property Item(ByVal index As Integer) As Object Implements System.Collections.IList.Item

Get

Return (obj(index))

End Get

Set(ByVal Value As Object)

obj(index) = Value

End Set

End Property

Public Sub Remove(ByVal value As Object) Implements System.Collections.IList.Remove

obj.Remove(value)

End Sub

Public Sub RemoveAt(ByVal index As Integer) Implements System.Collections.IList.RemoveAt

obj.RemoveAt(index)

End Sub

'Falta

Public Sub AddIndex(ByVal [property] As System.ComponentModel.PropertyDescriptor) Implements System.ComponentModel.IBindingList.AddIndex

End Sub

'Falta

Public Function AddNew() As Object Implements System.ComponentModel.IBindingList.AddNew

End Function

'Falta

Public ReadOnly Property AllowEdit() As Boolean Implements System.ComponentModel.IBindingList.AllowEdit

Get

End Get

End Property

'Falta

Public ReadOnly Property AllowNew() As Boolean Implements System.ComponentModel.IBindingList.AllowNew

Get

End Get

End Property

'Falta

Public ReadOnly Property AllowRemove() As Boolean Implements System.ComponentModel.IBindingList.AllowRemove

Get

End Get

End Property

'Falta

Public Sub ApplySort(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal direction As System.ComponentModel.ListSortDirection) Implements System.ComponentModel.IBindingList.ApplySort

End Sub

Public Function Find(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal key As Object) As Integer Implements System.ComponentModel.IBindingList.Find

Dim o As Integer

For o = 0 To obj.Count - 1

If [property].GetValue(obj(o)) = key Then

Return (o)

End If

Next

Return (-1)

End Function

'Falta

Public ReadOnly Property IsSorted() As Boolean Implements System.ComponentModel.IBindingList.IsSorted

Get

End Get

End Property

Public Event ListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs) Implements System.ComponentModel.IBindingList.ListChanged

'Falta

Public Sub RemoveIndex(ByVal [property] As System.ComponentModel.PropertyDescriptor) Implements System.ComponentModel.IBindingList.RemoveIndex

End Sub

'Falta

Public Sub RemoveSort() Implements System.ComponentModel.IBindingList.RemoveSort

End Sub

'Falta

Public ReadOnly Property SortDirection() As System.ComponentModel.ListSortDirection Implements System.ComponentModel.IBindingList.SortDirection

Get

End Get

End Property

'Falta

Public ReadOnly Property SortProperty() As System.ComponentModel.PropertyDescriptor Implements System.ComponentModel.IBindingList.SortProperty

Get

End Get

End Property

'Falta

Public ReadOnly Property SupportsChangeNotification() As Boolean Implements System.ComponentModel.IBindingList.SupportsChangeNotification

Get

End Get

End Property

Public ReadOnly Property SupportsSearching() As Boolean Implements System.ComponentModel.IBindingList.SupportsSearching

Get

Return (True)

End Get

End Property

'Falta

Public ReadOnly Property SupportsSorting() As Boolean Implements System.ComponentModel.IBindingList.SupportsSorting

Get

End Get

End Property

End Class







 

posted on Wednesday, October 13, 2004 1:39 AM by Dennes


 
03.UPDATE CALENDAR :
<October 2004>
SunMonTueWedThuFriSat
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

05.MY LINKS :

07.Subscriptions :

Subscriptions


© Copyright 2005 Microsoft Corporation. All Rights Reserved.
Terms of Use | Privacy Statement | Code of Conduct | Hosted by MaximumASP for Microsoft
WHO-BAR