2008-10-14 11 views
14

Actualmente estoy buscando una manera de recibir notificaciones cuando se agrega un niño a los niños visuales o lógicos.Ser notificado cuando el niño visual/lógico agregado/eliminado

Conozco el método Visual :: OnVisualChildrenChanged, pero no se aplica a mí, ya que no siempre puedo heredar y anular esta función. Estoy buscando un evento.

Entonces, ¿hay alguna forma de que se notifique al propietario de FrameworkElement/Visual cuando se agrega un elemento secundario?

Respuesta

1

Creo que FrameworkElement.Loaded y FrameworkElement.Unloaded se activan cuando se agrega y quita el control del Árbol visual, respectivamente. Sin embargo, las pocas veces que intenté hacer algo con ellos no pude lograr que disparasen de manera consistente (estaba usando Controladores de eventos de clase en ese momento, por lo que podría tener algo que ver con eso).

+0

Bueno, el niño recibe el FrameworkElement.Loaded, pero el padre no sabe que el niño realmente se creó y se le agregó. – decasteljau

1

Tal vez sería útil agregar al niño la referencia de mantenimiento de campo para el padre y enviar una notificación después de un cambio de nuevo a ella?

1

EDITAR:

Solo he pensado en algo. Si puede establecer un controlador cargado en cada elemento que aparece en su árbol visual, quizás podría hacerse con una técnica como esta (considere esta una idea MUY básica, como un comienzo hacia una posible solución):

public class ElementChildrenChangedEventArgs 
{ 
    public ElementChildrenChangedEventArgs(FrameworkElement parent, FrameworkElement child) 
    { 
     Parent = parent; 
     Child = child; 
    } 

    public FrameworkElement Parent { get; private set;} 
    public FrameworkElement Child { get; private set;} 
} 

public delegate void ChildrenChanged(ElementChildrenChangedEventArgs args); 

public static class ElementLoadedManager 
{ 
    private static readonly HashSet<FrameworkElement> elements = new HashSet<FrameworkElement>(); 

    public static void Process_Loaded(FrameworkElement fe) 
    { 
     FrameworkElement feParent = VisualTreeHelper.GetParent(fe) as FrameworkElement; 

     if (feParent != null) 
     { 
      if (elements.Contains(feParent)) 
      { 
       InvokeChildrenChanged(feParent, fe); 
      } 
     } 

     if (!elements.Contains(fe)) 
     { 
      elements.Add(fe); 
     } 

     fe.Unloaded += Element_Unloaded;   
    } 

    static void Element_Unloaded(object sender, RoutedEventArgs e) 
    { 
     FrameworkElement fe = sender as FrameworkElement; 
     elements.Remove(fe); 
     ClearUnloaded(fe); 
    } 

    static void ClearUnloaded(FrameworkElement fe) 
    { 
     fe.Unloaded -= Element_Unloaded; 
    } 

    public static event ChildrenChanged ChildrenChanged; 

    private static void InvokeChildrenChanged(FrameworkElement parent, FrameworkElement child) 
    { 
     ElementChildrenChangedEventArgs args = new ElementChildrenChangedEventArgs(parent, child); 

     ChildrenChanged changed = ChildrenChanged; 

     if (changed != null) changed(args); 
    } 
} 

La idea (y el requisito) sería invocar el método Process_Loaded (FrameworkElement) en el controlador Loaded de cada elemento, que es posible hacer con un poco de configuración de estilo/plantilla.

Y como Loaded es un evento enrutado, puede establecer el manejador solo en la ventana principal y buscar e.OriginalSource.

+0

Respuesta editada con algunas ideas. –

+0

Según MSDN, la estrategia de enrutamiento del evento Loaded no hace burbujas, es "directo". Por esta razón, me gustaría leer sus comentarios sobre si su solución (arriba) funciona. – Mark

2

No es más fácil de extender

System.Windows.Controls.UIElementCollection 

hacer la notificación y el uso

protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent) 

?

1

Puede utilizar un comportamiento adjunto en los elementos secundarios para generar un evento adjunto que se propaga desde los elementos secundarios a su elemento primario. O bien, en el evento cargado del niño, simplemente puede buscar el árbol lógico primario y llamar allí un método o establecer una propiedad (por ejemplo, incrementar el número de niños) para indicar que el niño está allí, dependiendo de lo que quieras que suceda con el padre. Si usa las propiedades de configuración de aproximación, también tendrá que manejar Descargada.

Cargado y descargado no siempre se levantan como se esperaba. Sin embargo, si usa DataTemplates para crear los controles secundarios, siempre deben dispararse cuando se crea y destruye un control, respectivamente.

Cuestiones relacionadas