Почему Silverlight ContentControls не собирает мусор? - PullRequest
6 голосов
/ 26 ноября 2010

Я изучал, почему некоторые из моих элементов управления не собирались мусором, и заметил, что легко предотвратить уничтожение простых элементов управления, которые наследуются от ContentControl.Вот пример:

Вот мой пользовательский ContentControl:

 public class MyCustomControl : ContentControl
{

    public MyCustomControl()
    {
        Debug.WriteLine("Constructed");
    }

    ~MyCustomControl()
    {
        Debug.WriteLine("Destroyed");
    }
}

Теперь, если я помещу его на страницу примерно так:

<navigation:Page x:Class="SimpleTestBed.Views.CustomControl" 
       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"
       mc:Ignorable="d"
       xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
             xmlns:local="clr-namespace:SimpleTestBed"
       d:DesignWidth="640" d:DesignHeight="480"
       Title="CustomControl Page">
<Grid x:Name="LayoutRoot">

    <StackPanel>
        <local:MyCustomControl>
            <TextBox Text="{Binding SomeProperty,Mode=TwoWay}"></TextBox>
        </local:MyCustomControl>
    </StackPanel>

</Grid>

Со следующим кодом позади:

 public partial class CustomControl : Page
{
    public CustomControl()
    {
        InitializeComponent();

        this.DataContext = new CustomControlViewModel();

        this.Unloaded += new RoutedEventHandler(OnUnloaded);
    }

    void OnUnloaded(object sender, RoutedEventArgs e)
    {
        this.DataContext = null;
    }

    // Executes when the user navigates to this page.
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    }



}

Тогда модель представления:

  public class CustomControlViewModel : INotifyPropertyChanged
{

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        RaisePropertyChanged(propertyName);
    }
    private void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion


    private string _someProperty = "Initial Value";
    public string SomeProperty
    {
        get { return _someProperty; }
        set
        {
            if (_someProperty != value)
            {
                string oldValue = _someProperty;
                _someProperty = value;
                OnPropertyChanged("SomeProperty");
                OnSomePropertyChanged(oldValue, value);
            }
        }
    }



    protected virtual void OnSomePropertyChanged(string oldValue, string newValue)
    {

    }


}

Теперь, когда я ухожу от этой страницы и пытаюсь собирать мусор с помощью GC.Collect (), до тех пор, покане внесено никаких изменений в текст в текстовом поле, ContentControl и Page уничтожены, как ожидается GC.Но если я отредактировал некоторый текст и ушел со страницы, а затем попытался выполнить GC.Collect (), ContentControl не собирает мусор.

Кто-нибудь может объяснить это поведение?

На самом деле, вы можете заставить GC собирать элемент управления, «мерцая» шаблоном элемента управления при выгрузке:

  void MyCustomControl_Unloaded(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine("MyCustomControl Unloaded");
        ControlTemplate oldTemplate = this.Template;
        this.Template = null;
        this.Template = oldTemplate;
    }

Я предполагаю, что это разрушает текущее визуальное дерево, теряя ссылкипервый компонент дерева к его родителю (пользовательский элемент управления).Это, безусловно, заставляет элемент управления вызывать OnApplyTemplate при перезагрузке элемента управления.

Это правильный шаблон для разработки элементов управления Silverlight без утечки?Если это так, мне кажется немного странным, что шаблон не удаляется автоматически при выгрузке элемента управления.

Хороший отчет об этом поведении будет высоко оценен, поскольку он подходит к сердцу жизненного цикла элементов управления Silverlight.

1 Ответ

0 голосов
/ 16 января 2011

Мой опыт показал, что утечки памяти в Silverlight вызваны двумя основными причинами:

  • События => Убедитесь, что вы удалили вложенные события один раз, когда это не нужно или в деструкторе класса.*
  • Templates => Решение определяет шаблоны в разделе ресурсов
...