そのため、MVVM + DataTemplate メソッドで WPF 3.5 を使用して、GUI に 2 つのビューをロードしています。アイテム コントロールのアイテム コンテナーの一部として生成されたアイテムがメモリに固定され、ビューがアンロードされた後でも GC されないことをメモリ プロファイリング中に観察しました。
テストを実行したところ、最も単純なコードでも再現可能であることがわかりました...自分で確認できます。
XAML:
<Window x:Class="ContentControlVMTest.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ContentControlVMTest"
Title="Window2" Height="300" Width="300">
<DockPanel LastChildFill="True">
<CheckBox Click="CheckBox_Click" Content="Test1?"
DockPanel.Dock="Top" Margin="5"/>
<ContentControl x:Name="contentControl">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:Test3}">
<TextBlock Text="{Binding C}" Margin="5"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Test1}">
<DockPanel LastChildFill="True" Margin="5">
<TextBlock Text="{Binding A}"
DockPanel.Dock="Top"
Margin="5"/>
<ListBox ItemsSource="{Binding Bs}"
DisplayMemberPath="B"
Margin="5"/>
</DockPanel>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</DockPanel>
</Window>
コードビハインド:
public class Test3
{
public string C { get; set; }
}
public class Test2
{
public string B { get; set; }
}
public class Test1
{
public string A { get; set; }
private List<Test2> _Bs;
public List<Test2> Bs
{
get
{
return _Bs;
}
set
{
_Bs = value;
}
}
}
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
this.KeyDown += Window_KeyDown;
}
private void Window_KeyDown
(object sender, System.Windows.Input.KeyEventArgs e)
{
if (Keyboard.IsKeyDown(Key.LeftCtrl))
if (Keyboard.IsKeyDown(Key.LeftShift))
if (Keyboard.IsKeyDown(Key.LeftAlt))
if (Keyboard.IsKeyDown(Key.G))
{
GC.Collect(2, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(2, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(3, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(3, GCCollectionMode.Forced);
}
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
if (((CheckBox)sender).IsChecked.GetValueOrDefault(false))
{
var x = new Test1() { A = "Test1 A" };
x.Bs = new List<Test2>();
for (int i = 1; i < 10000; i++ )
{
x.Bs.Add(new Test2() { B = "Test1 B " + i });
}
contentControl.Content = x;
}
else
{
contentControl.Content = new Test3() { C = "Test3 C" };
}
}
}
左 Shift + Alt + Ctrl + G で強制 GC を実行します。Test1
またはTest3
ビューとビュー モデルのすべてのアイテムは、正しくアンロードされた後に無効になります。ということで、予想通りです。
Test1
ただし、モデル (オブジェクトを含む) で生成されたコレクションはTest2
、メモリに固定されたままです。また、リストボックスの仮想化されていない項目の数を示しているため、配列がリストボックスの項目コンテナーによって使用される配列であることを示しています! Test1
この固定配列は、ビュー モードでビューを最小化または復元するとサイズが変わります。あるときは 16 アイテムで、次はプロファイリングすると 69 アイテムでした。
これは、WPF が項目コントロールで生成された項目の固定を実行することを意味します! 誰でもこれを説明できますか?これには重大な欠点がありますか?
ありがとう。