2009-03-20 4 views
5

Tengo una subclase de System.Windows.Forms.TreeView que se "vincula" manualmente a un conjunto de datos jerárquicos. Quiero que el usuario pueda editar las etiquetas del árbol y hacer que los cambios se reflejen en los datos. Así que me puse a LabelEdit verdadera y OnAfterLabelEdit hizo caso omiso a la suma de:¿Puedo insertar nodos en un TreeView durante AfterLabelEdit sin comenzar a editarlos?

protected override void OnAfterLabelEdit(NodeLabelEditEventArgs e) 
{ 
    base.OnAfterLabelEdit(e); 

    TreeNode node = e.Node; 

    if (PassesSomeValidation(e.Label)) 
    { 
     MyDataNode dataNode = node.Tag as MyDataNode; 
     dataNode.SomeBoundValue = e.Label; 

     int oldIndex = node.Index; 
     int newIndex = RepositionChangedDataNode(dataNode); 

     TreeNode parent = node.Parent; 
     parent.Nodes.RemoveAt(oldIndex); 
     parent.Nodes.Insert(newIndex, node); 
    } 
    else 
    { 
     e.CancelEdit = true; 
    } 
} 

RepositionChangedDataNode() re-ordena los datos y devuelve el índice en el que el nodo de cambio se movió después de la clasificación. Esperaba poder mover el nodo editado para reflejar este movimiento.

El problema es que esto hace que el nodo permanezca en modo de edición! Intenté llamar al EndEdit(), cloné el nodo antes de insertarlo, configurando LabelEdit en falso y devolviéndolo a verdadero, envolviendo el cambio en BeginUpdate()/EndUpdate(), y varias combinaciones de estas ideas, pero ninguna de ellas tiene ningún efecto.

El culpable parece ser la inserción. Incluso si intento insertar un nuevo nuevo nodo, entrará en modo de edición inmediatamente.

Entonces, ¿hay alguna manera de hacer que TreeView no se comporte de esta manera? Y si no, ¿hay una buena solución?

Algunas ideas que hemos considerado:

  1. Establecer un TreeViewNodeSorter personalizado. Sin embargo, preferiría no tener que ordenar mis datos dos veces.
  2. Establezca un indicador y demore el paso de quitar e insertar hasta algún punto después de AfterLabelEdit. Funciona para hacerlo durante WndProc, pero esto se siente como un gran error que de alguna manera puede fallar.
  3. Uso BeginInvoke() para empujar el paso de quitar a insertar de nuevo en la cola de mensajes, así:

    BeginInvoke(new MethodInvoker(delegate(
    { 
        parent.Nodes.RemoveAt(oldIndex); 
        parent.Nodes.Insert(newIndex, node); 
    })); 
    

    Esto funciona y parece más limpio para mí que # 2, pero sé que esto probablemente no es la forma en BeginInvoke() estaba destinado para ser utilizado, y que puede tener repercusiones que mi muy limitado conocimiento del mensaje bomba no puede predecir.

+0

Tengo el mismo problema: ¿qué terminaste haciendo? – Handleman

+0

Fui con la idea n. ° 3 por el momento. Parece estar funcionando bien hasta ahora. –

+0

Acabo de tener un problema similar al intentar ordenar TreeView en el evento AfterLabelEdit. Usé una solución similar a la tuya, y funcionó bien. Probablemente sea un error en TreeView ... –

Respuesta

0

Si está utilizando enlace de datos, ¿no debería la actualización de la fuente de datos (SomeBoundValue) desencadenar una actualización de los nodos? Tal vez puedas forzar al administrador de divisas a repoblar la vista en árbol ... Si te preocupa el rendimiento, puedes usar uno de los algoritmos de clasificación que funciona bien con datos que ya están casi ordenados (p. Ej., No se incluyen en el quicksort - merge o heapsort en mente)

O podría prescindir del enlace de datos por completo y manejar manualmente el reposicionamiento, ya que ya está a medio camino con RepositionChangedDataNode() ....

+0

TreeView no admite la vinculación de datos por sí mismo, por lo que estoy copiando manualmente el valor modificado a la fuente de respaldo. Manipular manualmente el reposicionamiento es exactamente lo que trato de hacer, pero está causando este comportamiento absurdo de no detener la edición. –

1

intentar crear un variable global, digamos:

private bool _allowEdit; 

inicializarlo a true,

en su método OnAfterLabelEdit la pusieron a false después de sus modificaciones:

... int oldIndex = node.Index; 
    int newIndex = RepositionChangedDataNode(dataNode); 

    TreeNode parent = node.Parent; 
    parent.Nodes.RemoveAt(oldIndex); 
    parent.Nodes.Insert(newIndex, node); 
    **_allowEdit = false;** 
} 
else ... 

luego capturar el evento OnBeforeLabelEdit de esta manera:

protected override void OnBeforeLabelEdit(NodeLabelEditEventArgs e) 
    { 
     base.OnBeforeLabelEdit(e); 
     e.CancelEdit = !_allowEdit; 
     _allowEdit = true; 
    } 

Me di cuenta de que justo después de que se active 'AfterLabelEdit', se restablece 'BeforeLabelEdit'. Es por eso que tienes que detenerlo allí mismo.

+0

Probé esto; no funciona El nodo insertado todavía entra en modo de edición. –

0

Puede intentar desenganchar su controlador OnEdit antes de agregar el nuevo nodo y volverlo a conectar después. He visto ese comportamiento antes y así es como lo manejé.

+0

Pero el problema no es que se llame a ningún controlador cuando no debería ser. Esto no ayudará. –

3

Si configura LabelEdit para TreeView en false, los nodos recién agregados no estarán en modo de edición.

Simplemente tiene que manejar el caso en el que el usuario desea editar una etiqueta: Cree un controlador para el evento MouseClick del TreeView, donde obtiene el nodo cliqueado por ubicación. Establezca LabelEdit en true y llame al BeginEdit(). Al final de su controlador para el evento AfterLabelEdit (y después de llamar al EndEdit(...) en un punto apropiado), configure LabelEdit en false nuevamente.

Esto funciona para mí, mientras que la solución con BeginInvoke solo cambió qué nodo estaba en modo de edición al final.

Cuestiones relacionadas