dimecres, 20 de juliol del 2011

"ContainerFromItem returns null" (or Nothing)

"ContainerFromItem returns null" (or Nothing) v.s. "Puedo quedarme embarazada con la regla":

Molts amics quan em troben pel carrer m'aturen i em dieun:

Quan treballo amb un treeView (o un listView) de silverlight i vull obtenir el container d'un node m'apareix l'error: "ContainerFromItem returns null"

Potser penseu que estic fent broma, però fixeu-vos que realment és un error molt habitual:


60Mil resultats que podem comparar-los amb altres cerques:



Anem a solucionar-ho, jo només m'hi he passat 3 hores per trobar quin és el motiu.
I no és un motiu, són dos:

1) En primer lloc, quan des d'un objecte X invoquem el mètode ContainerFromItem només busca els Items fills de l'objecte X.

Solució: Doncs cal invocar ContainerFromItem a l'objecte contenidor pare de l'objecte de negoci del qual volem el contenidor (ContenidorPare.ItemContainerGenerator) . Però, com obting el contenidor del pare? Doncs invocant el mètode ContainerFromItem al seu contenidor pare .... i així fins al node arrel on coneixem el contenidor pare que és conegut: TreeViewX.ItemContainerGenerator. LLavors cal usar recursió:

Public Function ContainerFromItem(ByVal item As objecteDeNegoci) As TreeViewItem
        Dim containerThatMightContainItem As TreeViewItem
        If IsNothing( item.parent ) Then
            containerThatMightContainItem = DirectCast(TreeViewX.ItemContainerGenerator.ContainerFromItem(item), TreeViewItem)
        Else
            Dim containerItemPare = ContainerFromItem(item.parent)
            containerThatMightContainItem = DirectCast(containerItemPare.ItemContainerGenerator.ContainerFromItem(item), TreeViewItem)
        End If
        Return containerThatMightContainItem
    End Function
2) Tot i que ja sabem baixar pels contenidors fins al nostre objecte de negoci, pot ser que encara el seu contenidor sigui Null, a que és degut? Doncs a que FINS QUE NO ES PINTA UN NODE NO SE LI CREA CONTENIDOR. Aleshores cal que estiguis segur que el node s'ha pintat:

Solució:
Primer: Expandir el pare:

Dim ccP = ContainerFromItem(objecteDeNegoci.parent)
ccP.IsExpanded = True
ccP.Visibility = Windows.Visibility.Visible

Segon: Forçar que es repinti. (Hi ha solucions alternatives amb events i tal)
ccP.UpdateLayout()

Ara ja estem en condicions de demanar el contenidor del fill:

Dim ccO = ContainerFromItem(objecteDeNegoci)
ccO.IsSelected = True

Si teniu dubtes de que als nodes pares no tinguin contenidor llavors heu de modificar el nostre mètode ContainerFromItem per tal que vagi expandir i fent UpdateLayout dels nodes intermitjos:


Public Function ContainerFromItem(ByVal item As objecteDeNegoci) As TreeViewItem
        Dim containerThatMightContainItem As TreeViewItem
        If IsNothing( item.parent ) Then
            containerThatMightContainItem = DirectCast(TreeViewX.ItemContainerGenerator.ContainerFromItem(item), TreeViewItem)
containerThatMightContainItem.IsExpanded = True
containerThatMightContainItem.UpdateLayout() Else Dim containerItemPare = ContainerFromItem(item.parent) containerThatMightContainItem = DirectCast(containerItemPare.ItemContainerGenerator.ContainerFromItem(item), TreeViewItem) End If Return containerThatMightContainItem End Function


Bé, espero que ja no us trobeu més amb aquest problema (ni amb l'altre). Si és així, please, deixa un comentari.

Cap comentari:

Publica un comentari a l'entrada