Question about Diagram.UnloadingClearsPartManager

Hello all

Regarding the API Reference of Diagram there is a sentence in the Remarks of the Property 'UnloadingClearsPartManager':
"If the diagram is inside a TabControl, this treats the value of UnloadingClearsPartManager as if it were false."
I'm wondering about the meaning of this sentence.
My current Application looks like this:
I have a Palette and a Diagram in a UserControl. The UserControl is added as Content to a TabItem inside a TabControl. If the TabItem is closed, the UserControl stays in Memory and is not freed. Even if I get the Content from the TabItem to set null, the UserControl still stays in Memory.
Is there any solution for this?
I'm using GoXam 1.2.2.4.
Thanks for any hint!
daprodigy

You are using either WPF or Silverlight 4, right?

The GoXam controls do not and should not have any bearing on the state of your UserControl. Unless you are doing something in an Unloaded event handler, your UserControl should remain in memory, although I’m not sure what should happen when one deletes tabs.

Each Diagram does establish its own Unloaded event handler. If it’s in the visual tree of a TabControl, nothing happens; if Diagram.UnloadingClearsPartManager is false, nothing happens; if it had already unloaded, nothing happens. Otherwise it removes all Parts from the Diagram, including removing any data-bindings that would otherwise cause Parts to be retained in memory.

Perhaps you can get rid of those (unexpected?) references due to data-binding by setting Diagram.Model to null.

Yes, I’m using WPF.

Setting the Diagrams Model to null took no effect.
I was wondering WHY there is this sentence in the Remarks, which I mentioned in my first post. The issue of having a disposed UserControl still in memory only occurs if I have the UserControl appearing inside a TabControl. If I add my UserControl to some Grid or ContentControl, there is no problem. So what's the special thing about TabControls?

When a Diagram is unloaded, by default it clears itself so that there are no data-bindings which might result in unintended references to Parts and indirectly to the Diagram as a whole. This helps avoid a lot of situations where there might otherwise be a “memory leak”.

When a Diagram is reloaded, it reconstitutes itself based on its Model. But in doing so some transient state may have been lost, which can be a problem in some situations.

That automatic clearing behavior can be avoided by setting that Diagram.UnloadingClearsPartManager property to false. You should do so if you know that you will be putting the Diagram back into the visual tree.

Unfortunately switching tabs in a TabControl may unload those controls. Since some people complained about the default behavior, we made it smarter by assuming the Diagram should not clear itself when unloaded from a TabControl.

But maybe we didn’t make it smart enough to handle your case.
We’ll have to consider that.

Thanks for your reply.

So in other words, If I have a Diagram inside a TabControl, the Diagram is never released and I have a memory leak?
And there is no other possibility to avoid that?

Well, if the Diagram is inside a TabControl, no, of course it isn’t released or cleared.

I assume you mean that when you remove the Diagram from inside a TabControl, it is never released.
That’s true, but you could invisibly add it to the visual tree outside of a TabControl, and then remove it. At least, I am hoping that will do what you want.

No.

I have the Diagram inside a UserControl which is the Content of a TabItem inside a TabControl.
When the TabItem is removed from the TabControl, the UserControl with the Diagram in it is not released.

But you already discovered how to make sure the Diagram is released when deleting a tab: remove your UserControl from the TabItem by setting its Content to null, insert that UserControl into your visual tree outside of a TabControl, and then remove it.

Or are you saying that what you discovered doesn’t work after all?

I wrote it in my first post.

Even if I null the Content of the TabItem, the UserControl stays in memory.

Yes, and then did you do the rest of what you discovered and what I suggested?

Sorry, I don’t know what you mean.

[quote]But you already discovered how to make sure the Diagram is released
when deleting a tab: remove your UserControl from the TabItem by setting
its Content to null, insert that UserControl into your visual tree
outside of a TabControl, and then remove it.[/quote]

This is my Remove-Method:

private void btnRemove_Click(object sender, RoutedEventArgs e)
{
if (tabControl.SelectedIndex != -1)
{
TabItem item = (TabItem)tabControl.Items[tabControl.SelectedIndex];
if (item.Content is UserControl)
{
UserControl contr = (UserControl)item.Content;
item.Content = null;
dummyGrid.Children.Clear();
dummyGrid.Children.Add(contr);
contr = null;
}
tabControl.Items.RemoveAt(tabControl.SelectedIndex);
item = null;
}
}
Am I missing something?

Is your dummyGrid in the visual tree?
If it is, then you also need to remove your UserControl from the dummyGrid.Children.
Another way of testing that is by removing two tab items, and seeing if the first Diagram is released.

If the dummyGrid isn’t in the visual tree, then I’m not convinced that there will be a Loaded event on your UserControl and on its Diagrams.

dummyGrid is in the VisualTree.

My actual Remove-Method:
private void btnRemove_Click(object sender, RoutedEventArgs e)
{
if (tabControl.SelectedIndex != -1)
{
TabItem item = (TabItem)tabControl.Items[tabControl.SelectedIndex];
if (item.Content is UserControl)
{
UserControl contr = (UserControl)item.Content;
item.Content = null;
dummyGrid.Children.Clear();
dummyGrid.Children.Add(contr);
contr = null;
dummyGrid.Children.Clear();
}
tabControl.Items.RemoveAt(tabControl.SelectedIndex);
item = null;
}
}
The UserControl still remains in memory.

OK, we’ll need to investigate why the UserControl/Diagram isn’t getting a Loaded event when it’s being added to your dummyGrid. Or if it is why it isn’t working as we’d expect.

The UserControl gets a Loaded Event when it’s being added to the dummyGrid.

Even if I remove the whole dummyGrid, the UserControl remains in the memory
Here is the instance path (.NET Memory Profiler) after removing the TabItem. The Diagram is removed from the UserControl (TestControl), but not the Palette ...

Hmm, the Palette is just a simple subclass of Diagram, so it isn’t treated differently.

Are your Palettes sharing a …Model? If so, maybe you could set Diagram.Model to null on the Palette.

No, Palette and Diagram have their own Model.