在 ItemsHost 面板上调用 Measure 后,无法更改 ItemsControl 上附加的 VirtualizationMode 属性
Cannot change the VirtualizationMode attached property on an ItemsControl after Measure is called on the ItemsHost panel
当我尝试将 ListView
上的 VirtualizationMode
设置为 Recycling
时,我从标题中得到错误:
Cannot change the VirtualizationMode attached property on an
ItemsControl after Measure is called on the ItemsHost panel.
我正在尝试以编程方式设置附加的 属性,但是当我尝试在 XAML 中定义 VirtualizationMode
时,设计器从标题中抛出相同的错误。有人遇到过类似的问题吗?
我在XAML中的观点是:
<Window x:Class="FinalVirtualizationApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:FinalVirtualizationApp"
mc:Ignorable="d"
Title="MainWindow" Height="900" Width="800"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextElement.FontWeight="Regular"
TextElement.FontSize="13"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{DynamicResource MaterialDesignFont}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<GroupBox Grid.Row="0" Header="UI virtualization options">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CheckBox Content="UI virtualization" VerticalAlignment="Center" IsChecked="{Binding IsUIVirtualization}"/>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="Container Recycling:" VerticalAlignment="Center"/>
<ComboBox Grid.Column="1" VerticalAlignment="Center" SelectedValue="{Binding ContainerRecyclingType}" SelectedValuePath="Content">
<ComboBoxItem>Recycling</ComboBoxItem>
<ComboBoxItem>Standard</ComboBoxItem>
</ComboBox>
</Grid>
<CheckBox Content="Deferred scrolling" Grid.Row="1" VerticalAlignment="Center" IsChecked="{Binding IsDeferredScrolling}">
</CheckBox>
<Grid Grid.Row="1" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="74*"/>
<ColumnDefinition Width="253*"/>
</Grid.ColumnDefinitions>
<Label Content="Scroll unit" VerticalAlignment="Center" Margin="0,0,0,1"/>
<ComboBox Grid.Column="1" VerticalAlignment="Center" SelectedValue="{Binding ScrollUnitType}" SelectedValuePath="Content" Grid.ColumnSpan="2" Margin="0,2,0,3">
<ComboBoxItem>Item</ComboBoxItem>
<ComboBoxItem>Pixel</ComboBoxItem>
</ComboBox>
</Grid>
</Grid>
</GroupBox>
<GroupBox Grid.Row="1" Header="Data virtualization">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<GroupBox Header="ItemsProvider">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<Label Content="Number of Items: "/>
<TextBox Width="60" Text="{Binding NumberOfItems}"/>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Label Content="Fetch delay(ms): "/>
<TextBox Width="60" Text="{Binding FetchDelay}"/>
</StackPanel>
</Grid>
</GroupBox>
<GroupBox Grid.Row="1" Header="Collection">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2,0,0">
<TextBlock Text="Type:" Margin="5" TextAlignment="Right" VerticalAlignment="Center"/>
<RadioButton x:Name="rbNormal" GroupName="rbGroup" Margin="5" Content="List(T)" VerticalAlignment="Center" Command="{Binding CollectionTypeChangeCommand}" CommandParameter="List"/>
<RadioButton x:Name="rbVirtualizing" GroupName="rbGroup" Margin="5" Content="VirtualizingList(T)" VerticalAlignment="Center" Command="{Binding CollectionTypeChangeCommand}" CommandParameter="VirtualizingList"/>
<RadioButton x:Name="rbAsync" GroupName="rbGroup" Margin="5" Content="AsyncVirtualizingList(T)" VerticalAlignment="Center" Command="{Binding CollectionTypeChangeCommand}" CommandParameter="AsyncVirtualizingList"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2,0,0">
<TextBlock Text="Page size:" Margin="5" TextAlignment="Right" VerticalAlignment="Center"/>
<TextBox x:Name="tbPageSize" Margin="5" Text="{Binding PageSize}" Width="60" VerticalAlignment="Center"/>
<TextBlock Text="Page timeout (s):" Margin="5" TextAlignment="Right" VerticalAlignment="Center"/>
<TextBox x:Name="tbPageTimeout" Margin="5" Text="{Binding PageTimeout}" Width="60" VerticalAlignment="Center"/>
</StackPanel>
</StackPanel>
</GroupBox>
</Grid>
</GroupBox>
<StackPanel Orientation="Horizontal" Grid.Row="2">
<TextBlock Text="Memory Usage:" Margin="5" VerticalAlignment="Center"/>
<TextBlock x:Name="tbMemory" Margin="5" Width="80" Text="{Binding MemoryUsage}" VerticalAlignment="Center"/>
<Button Content="Refresh" Margin="5" Width="100" VerticalAlignment="Center" Command="{Binding RefreshCommand}"/>
</StackPanel>
<ListView Grid.Row="3" Name="lvItems">
<ListView.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding DeviceName}">
<StackPanel>
</StackPanel>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
我尝试在此处设置 VirtualizationMode
:
public void SetUIVirtualizationOptions()
{
listView.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, IsUIVirtualization);
listView.SetValue(ScrollViewer.IsDeferredScrollingEnabledProperty, IsDeferredScrolling);
if(ContainerRecyclingType == "Recycling")
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Recycling);
else
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Standard);
if (ScrollUnitType == "Item")
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Item);
else
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Pixel);
}
编辑:我将列表视图传递给视图模型的 Window 代码是:
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel(lvItems);
}
}
以及代码的视图模型部分(减去 getter 和 setter 以减少 space 采取):
public class MainWindowViewModel : BindableBase
{
#region private fields
private ListView listView;
private bool isUIVirtualization;
private bool isDeferredScrolling;
private string containerRecyclingType;
private string scrollUnitType;
private int numberOfItems;
private int fetchDelay;
private string collectionType;
private int pageSize;
private int pageTimeout;
private string memoryUsage;
private DemoItemProvider itemsProvider;
#endregion
#region commands
public RelayCommand<string> CollectionTypeChangeCommand { get; set; }
public RelayCommand RefreshCommand { get; set; }
public RelayCommand<string> ContainerRecyclingTypeChangeCommand { get; set; }
public RelayCommand<string> ScrollUnitTypeChangeCommand { get; set; }
#endregion
public MainWindowViewModel(ListView lvItems)
{
this.listView = lvItems;
PageSize = 100;
PageTimeout = 30;
NumberOfItems = 1000000;
FetchDelay = 1000;
CollectionTypeChangeCommand = new RelayCommand<string>(CollectionTypeChangeFunc);
RefreshCommand = new RelayCommand(RefreshFunc);
ContainerRecyclingTypeChangeCommand = new RelayCommand<string>(ContainerRecyclingTypeChangeFunc);
ScrollUnitTypeChangeCommand = new RelayCommand<string>(ScrollUnitTypeChangeFunc);
// use a timer to periodically update the memory usage
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 1);
timer.Tick += timer_Tick;
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
MemoryUsage = string.Format("{0:0.00} MB", GC.GetTotalMemory(true) / 1024.0 / 1024.0);
}
#region command methods
public void CollectionTypeChangeFunc(string type)
{
CollectionType = type;
}
public void RefreshFunc()
{
SetUIVirtualizationOptions();
itemsProvider = new DemoItemProvider(NumberOfItems, FetchDelay);
if (collectionType == "List")
{
listView.ItemsSource = new List<DataItem>(itemsProvider.FetchRange(0, itemsProvider.FetchCount()));
}
else if (collectionType == "VirtualizingList")
{
listView.ItemsSource = new VirtualizingCollection<DataItem>(itemsProvider, pageSize);
}
else if (collectionType == "AsyncVirtualizingList")
{
listView.ItemsSource = new AsyncVirtualizingCollection<DataItem>(itemsProvider, pageSize, pageTimeout * 1000);
}
}
public void ContainerRecyclingTypeChangeFunc(string type)
{
ContainerRecyclingType = type;
}
public void ScrollUnitTypeChangeFunc(string type)
{
ScrollUnitType = type;
}
public void SetUIVirtualizationOptions()
{
listView.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, IsUIVirtualization);
listView.SetValue(ScrollViewer.IsDeferredScrollingEnabledProperty, IsDeferredScrolling);
if(ContainerRecyclingType == "Recycling")
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Recycling);
else
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Standard);
if (ScrollUnitType == "Item")
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Item);
else
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Pixel);
}
#endregion
}
VirtualizingStackPanel
的code source表示这个属性只能在面板初始化前设置:
/// <summary>
/// Attached property for use on the ItemsControl that is the host for the items being
/// presented by this panel. Use this property to modify the virtualization mode.
///
/// Note that this property can only be set before the panel has been initialized
/// </summary>
public static readonly DependencyProperty VirtualizationModeProperty =
DependencyProperty.RegisterAttached("VirtualizationMode", typeof(VirtualizationMode), typeof(VirtualizingStackPanel),
new FrameworkPropertyMetadata(VirtualizationMode.Standard));
你确实可以检查这个行为 later in the file:
//
// Set up info on first measure
//
if (HasMeasured)
{
VirtualizationMode oldVirtualizationMode = InRecyclingMode ? VirtualizationMode.Recycling : VirtualizationMode.Standard;
if (oldVirtualizationMode != virtualizationMode)
{
throw new InvalidOperationException(SR.Get(SRID.CantSwitchVirtualizationModePostMeasure));
}
}
else
{
HasMeasured = true;
}
并且没有办法(根据源代码)将此 HasMeasured
属性 设置回 False
,除非您销毁并重新创建 ListView
。
如消息所说:
Your not allowed to _change the VirtualizationMode attached property
on an ItemsControl after Measure is called on the ItemsHost panel.
这意味着,如果 ListView
已经显示正在使用的虚拟化机制并且您不能更改它。
如果您将XAML中的ListView
的Visibility
设置为Collapsed
并且稍后才将其设置为Visible
,那么您可以设置VirtualizationMode
在代码后面到希望的值,但只有一次(所以你不能在 ListView
变得可见后更改它)!
private void Button_Click(object sender, RoutedEventArgs e)
{
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Recycling);
listView.Visibility = Visibility.Visible;
}
XAML:
<ListView x:Name="listView" ... Visibility="Collapsed">
当我尝试将 ListView
上的 VirtualizationMode
设置为 Recycling
时,我从标题中得到错误:
Cannot change the VirtualizationMode attached property on an ItemsControl after Measure is called on the ItemsHost panel.
我正在尝试以编程方式设置附加的 属性,但是当我尝试在 XAML 中定义 VirtualizationMode
时,设计器从标题中抛出相同的错误。有人遇到过类似的问题吗?
我在XAML中的观点是:
<Window x:Class="FinalVirtualizationApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:FinalVirtualizationApp"
mc:Ignorable="d"
Title="MainWindow" Height="900" Width="800"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextElement.FontWeight="Regular"
TextElement.FontSize="13"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{DynamicResource MaterialDesignFont}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<GroupBox Grid.Row="0" Header="UI virtualization options">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CheckBox Content="UI virtualization" VerticalAlignment="Center" IsChecked="{Binding IsUIVirtualization}"/>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="Container Recycling:" VerticalAlignment="Center"/>
<ComboBox Grid.Column="1" VerticalAlignment="Center" SelectedValue="{Binding ContainerRecyclingType}" SelectedValuePath="Content">
<ComboBoxItem>Recycling</ComboBoxItem>
<ComboBoxItem>Standard</ComboBoxItem>
</ComboBox>
</Grid>
<CheckBox Content="Deferred scrolling" Grid.Row="1" VerticalAlignment="Center" IsChecked="{Binding IsDeferredScrolling}">
</CheckBox>
<Grid Grid.Row="1" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="74*"/>
<ColumnDefinition Width="253*"/>
</Grid.ColumnDefinitions>
<Label Content="Scroll unit" VerticalAlignment="Center" Margin="0,0,0,1"/>
<ComboBox Grid.Column="1" VerticalAlignment="Center" SelectedValue="{Binding ScrollUnitType}" SelectedValuePath="Content" Grid.ColumnSpan="2" Margin="0,2,0,3">
<ComboBoxItem>Item</ComboBoxItem>
<ComboBoxItem>Pixel</ComboBoxItem>
</ComboBox>
</Grid>
</Grid>
</GroupBox>
<GroupBox Grid.Row="1" Header="Data virtualization">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<GroupBox Header="ItemsProvider">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<Label Content="Number of Items: "/>
<TextBox Width="60" Text="{Binding NumberOfItems}"/>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Label Content="Fetch delay(ms): "/>
<TextBox Width="60" Text="{Binding FetchDelay}"/>
</StackPanel>
</Grid>
</GroupBox>
<GroupBox Grid.Row="1" Header="Collection">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2,0,0">
<TextBlock Text="Type:" Margin="5" TextAlignment="Right" VerticalAlignment="Center"/>
<RadioButton x:Name="rbNormal" GroupName="rbGroup" Margin="5" Content="List(T)" VerticalAlignment="Center" Command="{Binding CollectionTypeChangeCommand}" CommandParameter="List"/>
<RadioButton x:Name="rbVirtualizing" GroupName="rbGroup" Margin="5" Content="VirtualizingList(T)" VerticalAlignment="Center" Command="{Binding CollectionTypeChangeCommand}" CommandParameter="VirtualizingList"/>
<RadioButton x:Name="rbAsync" GroupName="rbGroup" Margin="5" Content="AsyncVirtualizingList(T)" VerticalAlignment="Center" Command="{Binding CollectionTypeChangeCommand}" CommandParameter="AsyncVirtualizingList"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2,0,0">
<TextBlock Text="Page size:" Margin="5" TextAlignment="Right" VerticalAlignment="Center"/>
<TextBox x:Name="tbPageSize" Margin="5" Text="{Binding PageSize}" Width="60" VerticalAlignment="Center"/>
<TextBlock Text="Page timeout (s):" Margin="5" TextAlignment="Right" VerticalAlignment="Center"/>
<TextBox x:Name="tbPageTimeout" Margin="5" Text="{Binding PageTimeout}" Width="60" VerticalAlignment="Center"/>
</StackPanel>
</StackPanel>
</GroupBox>
</Grid>
</GroupBox>
<StackPanel Orientation="Horizontal" Grid.Row="2">
<TextBlock Text="Memory Usage:" Margin="5" VerticalAlignment="Center"/>
<TextBlock x:Name="tbMemory" Margin="5" Width="80" Text="{Binding MemoryUsage}" VerticalAlignment="Center"/>
<Button Content="Refresh" Margin="5" Width="100" VerticalAlignment="Center" Command="{Binding RefreshCommand}"/>
</StackPanel>
<ListView Grid.Row="3" Name="lvItems">
<ListView.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding DeviceName}">
<StackPanel>
</StackPanel>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
我尝试在此处设置 VirtualizationMode
:
public void SetUIVirtualizationOptions()
{
listView.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, IsUIVirtualization);
listView.SetValue(ScrollViewer.IsDeferredScrollingEnabledProperty, IsDeferredScrolling);
if(ContainerRecyclingType == "Recycling")
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Recycling);
else
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Standard);
if (ScrollUnitType == "Item")
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Item);
else
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Pixel);
}
编辑:我将列表视图传递给视图模型的 Window 代码是:
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel(lvItems);
}
}
以及代码的视图模型部分(减去 getter 和 setter 以减少 space 采取):
public class MainWindowViewModel : BindableBase
{
#region private fields
private ListView listView;
private bool isUIVirtualization;
private bool isDeferredScrolling;
private string containerRecyclingType;
private string scrollUnitType;
private int numberOfItems;
private int fetchDelay;
private string collectionType;
private int pageSize;
private int pageTimeout;
private string memoryUsage;
private DemoItemProvider itemsProvider;
#endregion
#region commands
public RelayCommand<string> CollectionTypeChangeCommand { get; set; }
public RelayCommand RefreshCommand { get; set; }
public RelayCommand<string> ContainerRecyclingTypeChangeCommand { get; set; }
public RelayCommand<string> ScrollUnitTypeChangeCommand { get; set; }
#endregion
public MainWindowViewModel(ListView lvItems)
{
this.listView = lvItems;
PageSize = 100;
PageTimeout = 30;
NumberOfItems = 1000000;
FetchDelay = 1000;
CollectionTypeChangeCommand = new RelayCommand<string>(CollectionTypeChangeFunc);
RefreshCommand = new RelayCommand(RefreshFunc);
ContainerRecyclingTypeChangeCommand = new RelayCommand<string>(ContainerRecyclingTypeChangeFunc);
ScrollUnitTypeChangeCommand = new RelayCommand<string>(ScrollUnitTypeChangeFunc);
// use a timer to periodically update the memory usage
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 1);
timer.Tick += timer_Tick;
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
MemoryUsage = string.Format("{0:0.00} MB", GC.GetTotalMemory(true) / 1024.0 / 1024.0);
}
#region command methods
public void CollectionTypeChangeFunc(string type)
{
CollectionType = type;
}
public void RefreshFunc()
{
SetUIVirtualizationOptions();
itemsProvider = new DemoItemProvider(NumberOfItems, FetchDelay);
if (collectionType == "List")
{
listView.ItemsSource = new List<DataItem>(itemsProvider.FetchRange(0, itemsProvider.FetchCount()));
}
else if (collectionType == "VirtualizingList")
{
listView.ItemsSource = new VirtualizingCollection<DataItem>(itemsProvider, pageSize);
}
else if (collectionType == "AsyncVirtualizingList")
{
listView.ItemsSource = new AsyncVirtualizingCollection<DataItem>(itemsProvider, pageSize, pageTimeout * 1000);
}
}
public void ContainerRecyclingTypeChangeFunc(string type)
{
ContainerRecyclingType = type;
}
public void ScrollUnitTypeChangeFunc(string type)
{
ScrollUnitType = type;
}
public void SetUIVirtualizationOptions()
{
listView.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, IsUIVirtualization);
listView.SetValue(ScrollViewer.IsDeferredScrollingEnabledProperty, IsDeferredScrolling);
if(ContainerRecyclingType == "Recycling")
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Recycling);
else
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Standard);
if (ScrollUnitType == "Item")
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Item);
else
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Pixel);
}
#endregion
}
VirtualizingStackPanel
的code source表示这个属性只能在面板初始化前设置:
/// <summary>
/// Attached property for use on the ItemsControl that is the host for the items being
/// presented by this panel. Use this property to modify the virtualization mode.
///
/// Note that this property can only be set before the panel has been initialized
/// </summary>
public static readonly DependencyProperty VirtualizationModeProperty =
DependencyProperty.RegisterAttached("VirtualizationMode", typeof(VirtualizationMode), typeof(VirtualizingStackPanel),
new FrameworkPropertyMetadata(VirtualizationMode.Standard));
你确实可以检查这个行为 later in the file:
//
// Set up info on first measure
//
if (HasMeasured)
{
VirtualizationMode oldVirtualizationMode = InRecyclingMode ? VirtualizationMode.Recycling : VirtualizationMode.Standard;
if (oldVirtualizationMode != virtualizationMode)
{
throw new InvalidOperationException(SR.Get(SRID.CantSwitchVirtualizationModePostMeasure));
}
}
else
{
HasMeasured = true;
}
并且没有办法(根据源代码)将此 HasMeasured
属性 设置回 False
,除非您销毁并重新创建 ListView
。
如消息所说:
Your not allowed to _change the VirtualizationMode attached property on an ItemsControl after Measure is called on the ItemsHost panel.
这意味着,如果 ListView
已经显示正在使用的虚拟化机制并且您不能更改它。
如果您将XAML中的ListView
的Visibility
设置为Collapsed
并且稍后才将其设置为Visible
,那么您可以设置VirtualizationMode
在代码后面到希望的值,但只有一次(所以你不能在 ListView
变得可见后更改它)!
private void Button_Click(object sender, RoutedEventArgs e)
{
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Recycling);
listView.Visibility = Visibility.Visible;
}
XAML:
<ListView x:Name="listView" ... Visibility="Collapsed">