我有一个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>
实例的属性。
答案 0 :(得分:3)
当你这样做时
MaintenanceInfos.ItemsSource = maintenanceInfos;
在科学背后,WPF真的做了类似于的事情
MaintenanceInfos.ItemsSource = CollectionViewSource.GetDefaultView(maintenanceInfos)
该函数返回与IEnumerable
中传递的相同的ColectionView,并且ColectionView包含what the current selected item is之类的信息。我不是百分百肯定,但我认为该视图还缓存了基础IEnumerable
,并且只有在通过集合更改的事件通知视图时才重新查询它。
这就是您的神秘缓存可能来自的地方,在单独的窗口中从两个GetDefaultView
调用返回相同的ICollectionView
实例,并且它不会重新查询IEnumerable,因为它从未收到过集合从传入的对象中更改了事件。