Sabuncu
Sabuncu

Reputation: 5264

How to access an encompassing Canvas control from its children in WPF

I have a Canvas with the following XAML definition:

<Canvas Height="201" VerticalAlignment="Top"
        Name="myCanvas"
        KeyDown="KeyEvent" >
    <local:MyGlyphsElement x:Name="mge" />
    <Line Name="myLine" Stroke="Blue" StrokeThickness="2"></Line>
</Canvas>

In the code-behind file for the MyGlyphsElement control, how can I access myLine and myCanvas? (MyGlyphsElement is derived from FrameworkElement.)

My purpose is to be able to add controls at runtime to myCanvas children as well as manipulate myLine properties such as stroke width, etc.

EDIT:

public partial class MyGlyphsElement: FrameworkElement
    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);  // Good practice.
        ...
        Canvas cp = (Canvas)this.Parent;
        // Now what? How do I access myLine?

Upvotes: 0

Views: 764

Answers (1)

Tyler Kendrick
Tyler Kendrick

Reputation: 418

Make some nifty extensions for parsing the Visual Tree, like so (this will let you get an element by a specified name):

public static class DependentObjectExtensions
{
    public static IEnumerable<DependencyObject> GetChildren(this DependencyObject parent)
    {
        for (int i = 0, length = VisualTreeHelper.GetChildrenCount(parent); i < length; i++)
        {
            yield return VisualTreeHelper.GetChild(parent, i);
        }
    }

    public static T FindChild<T>(this DependencyObject parent, string name, bool drillDown = false)
        where T : FrameworkElement
    {
        if(parent != null)
        {
            var elements = parent.GetChildren().OfType<T>();
            return drillDown
                ? elements.Select(x => FindChild<T>(x, name, true)).FirstOrDefault(x => x != null)
                : elements.FirstOrDefault(x => x.Name == name);
        }
        return null;
    }
}

Then, change your MyGlyphsElement.OnRender to look like the following:

    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);

        var myLine = Parent.FindChild<Line>("myLine");
        //TODO: Do stuff with your line.
    } 

If you need further clarifications, let me know and I will edit my response according to your feedback.

Upvotes: 1

Related Questions