EDIT:
I just thought of something. If you are able to set a Loaded handler on each element which appears in your visual tree, perhaps it could be done with a technique like this (consider this a VERY basic idea, just as a start towards a possible solution):
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);
}
}
The idea (and requirement) would be to invoke the Process_Loaded(FrameworkElement) method in each element's Loaded handler, which is possible to do with some style/template setting.
And since Loaded is a routed event, you could set the handler only on the parent window and check for e.OriginalSource.