WPF';实例';在幕后生存
本文关键字:后生 实例 WPF | 更新日期: 2023-09-27 18:22:10
我有一个WPF Window子类。该窗口包含一个ItemsControl,它的ItemsSource在window子类ctor中初始化。该窗口使用ShowDialog()显示,每次都显示在一个新实例上。我看到的是,即使窗口和ItemsControl每次显示时都是新实例,分配给ItemsSource的IEnumerable也会以某种方式被记住(看起来),因此不会在每次显示窗口时调用GetEnumerator(),因此更改不会反映出来。但这种情况并不总是发生,有时会实际调用GetEnumerator()。如果每次为ItemsSource分配一个新的IEnumerable,则始终调用GetEnumerator。
是否有某种奇怪的缓存在幕后进行,或者可能是ItemsControl的底层实例(经常)被重用(可能受到垃圾收集的影响)?
XAML:
<Window x:Class="BalticWpfControlLib.SystemInfoWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BalticWpfControlLib"
Title="System Information" Height="400" Width="300" WindowStartupLocation="CenterOwner" >
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ItemsControl Name="MaintenanceInfos">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,0,0,1" Margin="4,4,4,0" BorderBrush="Gray">
<local:MaintenanceInfoUserControl Margin="0,0,0,4"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Window>
代码背后:
public partial class SystemInfoWindow : Window
{
public SystemInfoWindow(IEnumerable<IMaintenanceInfo> maintenanceInfos)
{
InitializeComponent();
System.Diagnostics.Debug.WriteLine("ItemsControl instance={0}", System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(MaintenanceInfos));
System.Diagnostics.Debug.Assert(null == MaintenanceInfos.ItemsSource);
MaintenanceInfos.ItemsSource = maintenanceInfos;
}
}
显示对话框的代码:
private void ShowSysInfo_Click(Object sender, RoutedEventArgs args)
{
var dlg = new SystemInfoWindow(facade.MaintenanceInfos);
dlg.Owner = Window.GetWindow(this);
dlg.ShowDialog();
}
facade.MaintenanceInfos
是一个始终返回相同IEnumerable<IMaintenanceInfo>
实例的属性。
进行时
MaintenanceInfos.ItemsSource = maintenanceInfos;
在科学背后,WPF确实在做一些类似的事情
MaintenanceInfos.ItemsSource = CollectionViewSource.GetDefaultView(maintenanceInfos)
该函数为IEnumerable
中传递的相同内容返回相同的ColectionView,并且ColectionView保存诸如当前所选项目的信息。我不能100%确定,但我认为该视图也缓存了底层IEnumerable
,并且只有在通过事件通知视图集合已更改时才重新查询它。
这就是神秘缓存的可能来源,同一个ICollectionView
实例是从单独窗口中的两个GetDefaultView
调用返回的,并且它不会重新查询IEnumerable,因为它从未接收到来自传入对象的集合更改事件。