0

I have a number of UserControl (a Grid with few Labels) being generated and added to Canvas in runtime. I have implemented drag-and-drop for each UserControl and node line (or connector line) between UserControls.

When I clear the UserControl with myCanvas.Children.Clear(), I received the following error in method Node_LayoutUpdated():

enter image description here

This is my UserControl:

public partial class Foo : UserControl
{
    public static readonly DependencyProperty AnchorPointProperty =
             DependencyProperty.Register(
            "AnchorPoint", typeof(Point), typeof(Foo),
                new FrameworkPropertyMetadata(new Point(0, 0),
                FrameworkPropertyMetadataOptions.AffectsMeasure));

    public Point AnchorPoint
    {
        get { return (Point)GetValue(AnchorPointProperty); }
        set { SetValue(AnchorPointProperty, value); }
    }

    private Canvas mCanvas;

    public Foo(Canvas canvas, bool isInput)
    {
        InitializeComponent();
        mCanvas = canvas;
        this.LayoutUpdated += Node_LayoutUpdated;
    }

    void Node_LayoutUpdated(object sender, EventArgs e)
    {
        Size size = RenderSize;
        Point ofs = new Point(size.Width / 2, size.Height / 2);
        AnchorPoint = TransformToVisual(this.mCanvas).Transform(ofs);
    }
}

Am I supposed to remove the DependencyProperty before removing the UserControl, and how? Can someone please explain what causes this error message and why?

KMC
  • 19,548
  • 58
  • 164
  • 253

1 Answers1

1

You problem is the last line of your code. The LayoutUpdated event is invoked right after you remove (Clear) the children of the Canvas. TransformToVisual doesn't work if the Control is already detached from the VisualTree. Subscribing to parent layout events is usually neither required nor a good idea. A quick workaround would be to detach the control before the Clear.

Add this code to your UserControl:

public void Detach()
{    
    this.LayoutUpdated -= Node_LayoutUpdated;
}

And this to your MainWindow:

foreach(WhateverYourControlTypeIs control in myCanvas.Children)
{
    control.Detach();
}
myCanvas.Children.Clear();
Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
  • Because the function Node_LayoutUpdated reside in the UserControl, I cannot detach it in MainWindows, and I get "The Name Node_LayoutUpdated does not exist in the current context". How do I detach it then? – KMC Sep 12 '16 at 02:49
  • @KMC Well, the easiest way would be to put the code in a public method of your UserControl (e.g. implement the `IDisposable` interface to your UserControl, put the detach code in there) and call it manually before removing it. You could also catch the exception and detach the event when an `InvalidOperationException` occurs. Instead of setting `mCanvas` in your constructor, you could [use the VisualTreeHelper to find the control's parent](http://stackoverflow.com/questions/636383/how-can-i-find-wpf-controls-by-name-or-type) on demand. – Manfred Radlwimmer Sep 12 '16 at 05:30
  • sorry but I do not follow you. What is the point of making Node_LayoutUpdated public? That would still not be accessible in MainWindows - what what do you mean by calling it manually? – KMC Sep 13 '16 at 05:33
  • Add a public method to your UserControl. Name that method `Detach`. In that method, add `this.LayoutUpdated -= Node_LayoutUpdated;`. Before you call `myCanvas.Children.Clear()` in your MainWindow, iterate through all UserControls in `myCanvas.Children`. Call `Detach` on each of them. – Manfred Radlwimmer Sep 13 '16 at 06:10