在ItemsHost面板上调用Measure后,无法更改ItemsControl上的VirtualizationMode附加属性

当我尝试将Virtualizationmode上的ListView设置为Recycling时,标题出现错误:

  

无法更改虚拟化模式的附加属性   在ItemsHost面板上调用Measure之后的ItemsControl。

我试图以编程方式设置附加属性,但是当我尝试在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,1"/>
                    <ComboBox Grid.Column="1" VerticalAlignment="Center" SelectedValue="{Binding ScrollUnitType}" SelectedValuePath="Content" Grid.ColumnSpan="2" Margin="0,2,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,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,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);
}

编辑:我将listview传递给viewmodel的背后的我的Window代码是:

    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel(lvItems);
        }
    }

代码的viewmodel部分(减去getter和setter以减少占用的空间):

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,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
    }
zyvip520 回答:在ItemsHost面板上调用Measure后,无法更改ItemsControl上的VirtualizationMode附加属性

VirtualizingStackPanel的{​​{3}}表示只能在面板初始化之前设置此属性:

/// <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));

您确实可以检查此行为code source

//
// 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

,

消息显示为

  

您不允许_change VirtualizationMode附加属性   在ItemsHost面板上调用Measure之后的ItemsControl上。

这意味着,如果已经显示ListView的虚拟化机制正在使用,则您将无法对其进行更改。

如果您在XAML中将Visibility中的ListView设置为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">
本文链接:https://www.f2er.com/3143640.html

大家都在问