tags:

views:

19

answers:

2

So for my application I just have an image loaded and then in a grid in a tab item. After clicking on a button I create a new tab item with associated code to load other things. However, on going back to the first tab, I am met with this error:

"Must disconnect specified child from current parent Visual before attaching to new parent Visual."

Specifically here:

    public class VisualsHost : FrameworkElement
{

    DrawingVisual _square;

    public VisualsHost()
    {
        _square = new DrawingVisual();
        this.Loaded += new RoutedEventHandler(OnLoaded);
    }

    public void OnLoaded(object sender, RoutedEventArgs e)
    {

        AddVisualChild(_square);
        AddLogicalChild(_square);
    }

This is just my container for my selection square I use for my content in the main tab.

So I am wondering, what exactly is happening here and how would I go about fixing this?

A brief structure of the content in my first tab is:

tabcontrol> dockpanel ->listbox -> grid (itemspanelcontainer style) -> listboxitems...

+1  A: 

The Loaded event gets called each time you select the tab thus attempting to add _square again!

The Loaded event is not necessarily only called once when first Loaded - the element can potentially be Loaded again for example if you were using system themes and changed your system theme all visual elements are re loaded.. In your case the visual tree is somehow being invalidated again - maybe because your binding to the Image is read again (if that is reason it may be good idea to change your binding to OneTime too). More info here: http://msdn.microsoft.com/en-us/library/ms754221.aspx and here: http://blogs.msdn.com/b/mikehillberg/archive/2006/09/19/loadedvsinitialized.aspx

UPDATE: From a comment in the 2nd link above, applicable in your case:

"If I may add the Loaded Event is also raised when ever a UI Element is loaded and unloaded. Such a case would be if you have a button named 'x' in Tab 'A', when the user switches to Tab 'B' an UnLoaded event is raised for x. When the user switches back to Tab A an Loaded event is raised for x, but not an Initialized event..."

You should be able to confirm if this is indeed the case with a breakpoint while debugging. If it is: you could use a flag to prevent the event doing anything or remove the event after it has run:

public class VisualsHost : FrameworkElement
{
  bool hasLoaded = false;
  DrawingVisual _square;

  public VisualsHost()
  {
    _square = new DrawingVisual();
    this.Loaded += new RoutedEventHandler(OnLoaded);
  }

  public void OnLoaded(object sender, RoutedEventArgs e)
  {
    if(!hasLoaded)
    {
      AddVisualChild(this._square);
      AddLogicalChild(this._square);
      this.hasLoaded = true;
      this.Loaded -= OnLoaded; // unnecessary if using the hasLoaded flag
    }
  }
}
Mrk Mnl
The main question is though, what happens when I go to that new tab? Is a new tree created or something and the old one wiped out? Obviously the old one isn't. To me it makes more sense for WPF to have the memory to know the structure and state of the previous visual/logical tree on each switch.
Ilya
Nothing new is created - a lesser know fact: the Loaded event is not only called once when first Loaded - the element can potentially be Loaded again for example if you were using system themes and changed your system theme all visual elements are re loaded.. In your case the visual tree is somehow being invalidated again - maybe because your binding to the Image is read again (if that is reason it may be good idea to change your binding to OneTime too). More info here: http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.loaded.aspx
Mrk Mnl
Upon learning this myself I had to add checks that my Loaded event handlers only ran once all over my code..
Mrk Mnl
A: 

Or if you are using KM controls (your grid?) you may need to upgrade: http://social.msdn.microsoft.com/forums/en-US/wpf/thread/321f9721-ca38-41ca-b851-7667895d6d84

Mrk Mnl