Unity remove / destroy control question
Hey all, I'm slowly figuring out all the little details about the Unity / NoesisGUI integration, but one thing I'm a bit stuck on is how a control gets removed and destroyed at runtime if so desired and the lifetime of UserControls. I've got a basic setup to test this, however I a few odd things as I run this code.
First I notice when I run the scene. I get 2 calls to the default constructor followed by a single call to the destructor. Secondly, when I remove the UserControl from the list of children, the test window is no longer visible as expected, however I do not receive a destructor call. So I assume there are still references somewhere, but given this simple test case, I'm drawing a blank. Any insight would be greatly appreciated.
MainWindow.xaml
TestWindow.xaml
TestWindow.cs
First I notice when I run the scene. I get 2 calls to the default constructor followed by a single call to the destructor. Secondly, when I remove the UserControl from the list of children, the test window is no longer visible as expected, however I do not receive a destructor call. So I assume there are still references somewhere, but given this simple test case, I'm drawing a blank. Any insight would be greatly appreciated.
MainWindow.xaml
Code: Select all
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:noesis="clr-namespace:NoesisGUIExtensions" xmlns:test="clr-namespace:Test"
RenderTransformOrigin="0.5,0.5">
<Grid x:Name="LayoutRoot">
<five:TestWindow/>
</Grid>
</Page>
Code: Select all
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:noesis="clr-namespace:NoesisGUIExtensions"
mc:Ignorable="d" x:Class="Test.TestWindow" x:Name="TestWindowControl">
<Grid x:Name="WindowRoot" Width="400" Height="200" Background="White">
<Button x:Name="CloseButton" Content="Button"/>
</Grid>
</UserControl>
Code: Select all
using Noesis;
using System;
namespace Test
{
[Noesis.Extended]
[Noesis.UserControlSource("Assets/GUI/TestWindow.xaml")]
public class TestWindow: Noesis.UserControl
{
public TestWindow()
{
UnityEngine.Debug.Log("Default Contstructor");
}
~TestWindow()
{
UnityEngine.Debug.Log("Default Destructor");
}
public void OnPostInit()
{
Button button = FindName<Button>("CloseButton");
button.Click += OnButtonClick;
}
public void OnButtonClick(BaseComponent sender, RoutedEventArgs e)
{
FrameworkElement framElem = GetParent();
Grid grid = framElem.As<Grid>();
if (grid != null)
{
UnityEngine.Debug.Log("Grid Element Name: " + grid.GetName());
UIElementCollection collection = grid.GetChildren();
collection.Remove(this);
}
}
}
}
Re: Unity remove / destroy control question
What happens when you remove "button.Click += OnButtonClick;" and instead just remove it after some time? I'm curious, since callbacks attached to native objects seem to one of the more common ways for memory leaks to show up.
-
sfernandez
Site Admin
- Posts: 2991
- Joined:
Re: Unity remove / destroy control question
Loading of a xaml file takes two steps:
- All objects in the tree are created, thus, its constructors are called.
- All the objects in the tree are initialized. During initialization the UserControl loads its contents from the xaml specified in the UserControlSource attribute. This is why your UserControl constructos is called again, although that instance will be discarded and its content will be connected to the first UserControl instance.
About the destructor, it gets called when all strong references from C# are freed, and object is disconnected from the tree. In your test, when you attach a handler to the Click event, the delegate stored keeps a strong reference to your UserControl. And this strong reference is the one that prevents the object from being destroyed.
I changed your test to the following:
And the destructor is called just after you click the button and the GC collects the object.
- All objects in the tree are created, thus, its constructors are called.
- All the objects in the tree are initialized. During initialization the UserControl loads its contents from the xaml specified in the UserControlSource attribute. This is why your UserControl constructos is called again, although that instance will be discarded and its content will be connected to the first UserControl instance.
About the destructor, it gets called when all strong references from C# are freed, and object is disconnected from the tree. In your test, when you attach a handler to the Click event, the delegate stored keeps a strong reference to your UserControl. And this strong reference is the one that prevents the object from being destroyed.
I changed your test to the following:
Code: Select all
namespace Test
{
[Noesis.Extended]
[Noesis.UserControlSource("Assets/Test/TestWindow.xaml")]
public class TestWindow : Noesis.UserControl
{
// ...
public void OnButtonClick(BaseComponent sender, RoutedEventArgs e)
{
Button button = FindName<Button>("CloseButton");
button.Click -= OnButtonClick;
FrameworkElement framElem = GetParent();
Grid grid = framElem.As<Grid>();
if (grid != null)
{
UnityEngine.Debug.Log("Grid Element Name: " + grid.GetName());
UIElementCollection collection = grid.GetChildren();
collection.Remove(this);
}
}
}
}
Re: Unity remove / destroy control question
Doh, I knew it had to be something stupid like that. Thanks for the answer.
Who is online
Users browsing this forum: Ahrefs [Bot], Google [Bot] and 20 guests