Spencer Ruport
Spencer Ruport

Reputation: 35117

Finding draw order on WPF Canvas.Children Issue

I needed to determine the draw order of the children contained in a canvas. So I ran across this Q/A:

How to compare the relative Z order of two WPF controls that are part of the same logical/visual tree?

This works perfectly most of the time but sometimes I get an error from this code:

private Panel FindWindowRoot(FrameworkElement child)
{
    FrameworkElement current = child;
    while(current as Window == null)
    {
        current = (FrameworkElement)VisualTreeHelper.GetParent(current); 
    }
    return ((Window)current).Content as Panel;
}

The call VisualTreeHelper.GetParent(current) ends up throwing an exception "Value cannot be null."

Here's one example of how I use the DrawOrderComparer.

ucVertexControl Control = new ucVertexControl(vertex);
cnvDrawingArea.Children.Add(Control);
SortedChildren = cnvDrawingArea.Children.OfType<FrameworkElement>().OrderByDescending(x => x, new Classes.DrawOrderComparer()).Cast<UIElement>().ToList();

My theory is that the sorting is occurring before the new control even has a parent defined because that gets set later by some event. Problem is I don't know what event that is and if I can listen for it.

Anyone have any ideas?

Upvotes: 1

Views: 1082

Answers (1)

Spencer Ruport
Spencer Ruport

Reputation: 35117

I believe I found a solution.

I don't know of any event that would fire from the canvas but I do know that each of my user controls have a Loaded event. So I changed this:

ucVertexControl Control = new ucVertexControl(vertex);
cnvDrawingArea.Children.Add(Control);
SortedChildren = cnvDrawingArea.Children.OfType<FrameworkElement>().OrderByDescending(x => x, new Classes.DrawOrderComparer()).Cast<UIElement>().ToList();

To this:

ucVertexControl Control = new ucVertexControl(vertex);
Control.Loaded += new RoutedEventHandler(Control_Loaded);
cnvDrawingArea.Children.Add(Control);

The Control_Loaded function just turns around and calls this method:

private void UpdateSortedChildren()
{
    if (cnvDrawingArea.Children.OfType<FrameworkElement>().Any(x => !x.IsLoaded)) return;
    SortedChildren = cnvDrawingArea.Children.OfType<FrameworkElement>().OrderByDescending(x => x, new Classes.DrawOrderComparer()).Cast<UIElement>().ToList();
}

Since there are times when I'm adding multiple children in a single call the method will only execute once all the controls have loaded. The errors have gone away so hopefully that was the issue.

Upvotes: 1

Related Questions