WPF'实例'在幕后幸存?

时间:2015-11-16 15:49:39

标签: c# wpf

我有一个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>实例的属性。

1 个答案:

答案 0 :(得分:3)

当你这样做时

MaintenanceInfos.ItemsSource = maintenanceInfos;
在科学背后,WPF真的做了类似于

的事情
MaintenanceInfos.ItemsSource = CollectionViewSource.GetDefaultView(maintenanceInfos)

该函数返回与IEnumerable中传递的相同的ColectionView,并且ColectionView包含what the current selected item is之类的信息。我不是百分百肯定,但我认为该视图还缓存了基础IEnumerable,并且只有在通过集合更改的事件通知视图时才重新查询它。

这就是您的神秘缓存可能来自的地方,在单独的窗口中从两个GetDefaultView调用返回相同的ICollectionView实例,并且它不会重新查询IEnumerable,因为它从未收到过集合从传入的对象中更改了事件。