visual tutorial studio .net wpf

.net - tutorial - wpf vs winforms



Ser notificado cuando el niño visual/lógico agregado/eliminado (5)

Actualmente estoy buscando una forma de recibir notificaciones cuando se agrega un niño a los niños visuales o lógicos.

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 manera para que se notifique al propietario de FrameworkElement / Visual cuando se agrega un elemento secundario?


Creo que FrameworkElement.Loaded y FrameworkElement.Unloaded se activan cuando el control se agrega y elimina del Visual Tree, 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).


Tal vez valdría la pena agregar a la referencia de mantenimiento de campo del niño a los padres y enviar una notificación después de un cambio de nuevo a ella?


EDITAR:

Solo pensé 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, solo 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, lo que es posible hacer con alguna configuración de estilo / plantilla.

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


¿No es más fácil extender

System.Windows.Controls.UIElementCollection

para hacer la notificación y el uso

protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)

?


Puede usar un comportamiento adjunto en los elementos secundarios para generar un evento adjunto que se propaga desde los elementos secundarios a sus elementos principales. O bien, en el evento cargado del niño, puede simplemente buscar al padre en el árbol lógico 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 plantean como se esperaba. Sin embargo, si usa DataTemplates para crear los controles secundarios, siempre deben dispararse cuando se crea y destruye un control, respectivamente.