Ответ 1
Разве не проще расширить
System.Windows.Controls.UIElementCollection
чтобы сделать уведомление и использовать
protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)
?
В настоящее время я ищу способ уведомления, когда ребенок добавляется к визуальным или логическим детям.
Мне известен метод Visual:: OnVisualChildrenChanged, но он не применяется ко мне, так как я не всегда могу наследовать и переопределять эту функцию. Я ищу событие.
Итак, есть ли способ, чтобы владелец FrameworkElement/Visual был уведомлен о добавлении ребенка?
Разве не проще расширить
System.Windows.Controls.UIElementCollection
чтобы сделать уведомление и использовать
protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)
?
Я считаю, что FrameworkElement.Loaded и FrameworkElement.Unloaded, когда элемент управления добавляется и удаляется из визуального дерева соответственно. Тем не менее, несколько раз, когда я пытался что-то с ними сделать, я не мог заставить их стрелять последовательно (в то время я использовал обработчики событий класса, так что это могло бы иметь к этому какое-то отношение).
Может быть, стоит добавить к дочернему полю ссылку на родителя и отправить уведомление после изменения обратно к нему?
EDIT:
Я только что подумал. Если вы можете установить обработчик Loaded для каждого элемента, который появляется в вашем визуальном дереве, возможно, это может быть сделано с помощью такой техники (рассмотрите это ОЧЕНЬ основную идею, как начало для возможного решения):
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);
}
}
Идея (и требование) заключалась бы в вызове метода Process_Loaded (FrameworkElement) в каждом элементе Loaded handler, который можно использовать с некоторыми настройками стиля/шаблона.
И поскольку Loaded является маршрутизируемым событием, вы можете установить обработчик только в родительском окне и проверить e.OriginalSource.
Вы можете использовать прикрепленное поведение дочерних элементов, чтобы поднять присоединенное событие, которое пузырится от дочерних элементов до их родителя. Или, в дочернем загруженном событии, вы можете просто найти родителя в логическом дереве и либо вызвать там метод, либо установить свойство (например, приращение дочернего счета, например), чтобы сигнализировать о том, что у него есть ребенок, в зависимости от того, что вы хотите совершить на родителях. Если вы используете свойства настройки подхода, вам также придется обрабатывать Unloaded.
Загрузка и выгрузка не всегда повышаются, как ожидалось. Однако, если вы используете DataTemplates для создания дочерних элементов управления, их всегда следует запускать, когда элемент управления создается и уничтожается соответственно.