簡體   English   中英

從包裝面板中清除子控件不會清除 memory 和參考

[英]clearing child controls from wrappanel does not clear memory and references

問題

我有一個包裝面板,用於將標簽應用於圖像。 可以添加和刪除標簽: 在此處輸入圖像描述

問題如下:刪除元素后,memory 不會被釋放,也不會被垃圾回收。

這就是我添加控件的方式:

foreach (MetadataAttribute attribute in metadata.attributes)
{
    this.Attributes_StackPanel.Children.Add(new Attribute(attribute));
}

這就是我最初刪除元素的方式:

this.Attributes_StackPanel.Children.Clear();

我試過的

我找到了有關該主題的多個資源和問題,但似乎沒有一個對我有用:

  • 清除前必須將名稱屬性設置為 null
  • 必須清除網格和堆棧面板
  • 所有引用都應該被清除
  • 元素本身應該被清除
  • 應清除父項的名稱屬性

我在帖子中徘徊,直到我以這樣的令人厭惡的方式結束:

父母:

/// <summary>
/// clears the attribute panel to prepare for new metadata to be loaded
/// </summary>
private void ClearAttributesPanel()
{
    for(int i = this.Attributes_StackPanel.Children.Count-1; i > 0; i--)
    {

        Attribute attr = (Attribute)this.Attributes_StackPanel.Children[i];
        attr.Delete();
        attr = null;
    }
}

xaml:

<UserControl x:Class="Minter_UI.Attribute"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Minter_UI"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800" Padding="0.1cm, 0.1cm, 0, 0">
    <Grid x:Name="Main_Grid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition MinWidth="1cm"></ColumnDefinition>
            <ColumnDefinition Width="0.5cm"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <StackPanel x:Name="Stack_Panel"  Orientation="Vertical" Grid.Row="0">
            <ComboBox x:Name="TraitType_ComboBox" IsEditable="True" Text="TraitType" SelectionChanged="TraitType_ComboBox_SelectionChanged"></ComboBox>
            <ComboBox x:Name="Value_ComboBox" IsEditable="True" Text="Value"></ComboBox>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <Label Content="MinValue" Grid.Column="0"></Label>
                <Label Content="MaxValue" Grid.Column="1"></Label>
                <TextBox x:Name="MinValue_TextBox" Grid.Row="1" Grid.Column="0"></TextBox>
                <TextBox x:Name="MaxValue_TextBox" Grid.Row="1" Grid.Column="1"></TextBox>
            </Grid>
            
        </StackPanel>
        
        <Button x:Name="Delete_Button" Content="X" Background="LightCoral" Grid.Column="1" Click="Delete_Button_Click"></Button>
    </Grid>
</UserControl>

屬性刪除:

public void Delete()
{
    // unregister events
    this.TraitType_ComboBox.SelectionChanged -= this.TraitType_ComboBox_SelectionChanged;
    this.Delete_Button.Click -= this.Delete_Button_Click;
    // main grid
    this.Main_Grid.Children.Clear();
    this.Main_Grid = null;
    // stack panel
    this.Stack_Panel.Children.Clear();
    this.Stack_Panel = null;
    // textboxes
    this.MinValue_TextBox.Text = null;
    this.MinValue_TextBox = null;
    this.MaxValue_TextBox.Text= null;
    this.MaxValue_TextBox = null;
    //comboboxes
    this.TraitType_ComboBox.ItemsSource= null;
    this.TraitType_ComboBox.SelectedItem= null;
    this.TraitType_ComboBox.Text= null;
    this.TraitType_ComboBox = null;
    this.Value_ComboBox.ItemsSource = null;
    this.Value_ComboBox.SelectedItem = null;
    this.Value_ComboBox.Text = null;
    this.Value_ComboBox = null;
    // delete button
    this.Delete_Button.Content = null;
    this.Delete_Button = null;
    // clear all x:name properties
    this.UnregisterName("Stack_Panel");
    this.UnregisterName("MinValue_TextBox");
    this.UnregisterName("MaxValue_TextBox");
    this.UnregisterName("TraitType_ComboBox");
    this.UnregisterName("Value_ComboBox");
    this.UnregisterName("Main_Grid");
    this.UnregisterName("Delete_Button");
    // remove self from parent
    ((Panel)this.Parent).Children.Remove(this);
}

不過,這不起作用。 在足夠的重新加載之后,我可以在堆中找到數千個對組合框和文本面板以及哈希表的引用。 一段時間后,垃圾收集器變得瘋狂但從未真正清除任何元素。

我不知道這是不是這樣做的方法,但它有效:

  1. 添加一個 function 以重新填充子控件 xaml.cs 的屬性:
public void SetAttribute(MetadataAttribute attribute)
{
    // you need to extend the function, its just an example
    this.TraitType_ComboBox.Text = attribute.trait_type.ToString();
    this.Value_ComboBox.Text = attribute.@value.ToString();
    this.MinValue_TextBox.Text = attribute.min_value.ToString();
    this.MaxValue_TextBox.Text = attribute.max_value.ToString();
}
  1. 對於保存集合的父級,添加一個隊列並調整 remove function 以將元素添加到隊列而不是銷毀它們:
Queue<Attribute> AttributeReuseElements = new Queue<Attribute>();
private void ClearAttributesPanel()
{
    for(int i = this.Attributes_StackPanel.Children.Count-1; i > 0; i--)
    {
        AttributeReuseElements.Enqueue((Attribute)this.Attributes_StackPanel.Children[i]);
        this.Attributes_StackPanel.Children.RemoveAt(i);
    }
}
  1. 加載元素后,回收先前從隊列中刪除的元素:
foreach (MetadataAttribute attribute in CollectionInformation.Information.LikelyAttributes)
{
    if (AttributeReuseElements.Count > 0)
    {
        Attribute attr = AttributeReuseElements.Dequeue();
        attr.SetAttribute(attribute);
        this.Attributes_StackPanel.Children.Add(attr);
    }
    else
    {
        this.Attributes_StackPanel.Children.Add(new Attribute(attribute));
    }
}

這不會忽略手動按下控件的刪除按鈕導致的 memory 泄漏,但這可能可以忽略不計。 但是,無論何時重新加載信息,元素都會被回收而不是被銷毀並重新創建。

如果您不確保正確清除所有字段和值,這可能會產生一些影響。 例如,您可能會從 previus 屬性中找到值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM