rcalt2vt
Topic Author
Posts: 17
Joined: 21 Feb 2014, 22:59

Unity remove / destroy control question

15 Jul 2014, 17:59

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
<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>
TestWindow.xaml
<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>
TestWindow.cs
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);
            }
        }
    }
}
 
wckdspn
Posts: 67
Joined: 18 Aug 2012, 23:14

Re: Unity remove / destroy control question

15 Jul 2014, 23:43

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.
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: Unity remove / destroy control question

15 Jul 2014, 23:59

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:
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);
            }
        }
    }
}
And the destructor is called just after you click the button and the GC collects the object.
 
rcalt2vt
Topic Author
Posts: 17
Joined: 21 Feb 2014, 22:59

Re: Unity remove / destroy control question

16 Jul 2014, 00:54

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