Ich habe kürzlich ein Virtualisierungsproblem bekommen und habe es auf den folgenden Code eingegrenzt.ItemsControl mit einer Höhe von * innerhalb eines ItemsControls virtualisieren
Der Grund, warum die Virtualisierung im folgenden Snippet nicht funktioniert, liegt an der Tatsache, dass das Kind keine bestimmte Höhe hat. Also meine Vermutung ist, dass es für immer expandiert und Virtualisierung bricht.
Wenn das Kind eine bestimmte Höhe erhält, wird das Problem behoben, aber dann wird die Benutzeroberfläche zu zwei unansehnlichen Bildlaufleisten, wenn ich eine Bildlaufleiste durch den gesamten Inhalt der Elementsteuerelemente scrollen möchte (ob untergeordnet oder nicht).
Meine Frage ist, ist das möglich? wenn ja, wie kann ich das erreichen? Irgendwie muss das Kind die Größe seiner selbst berechnen, ohne die Virtualisierung zu unterbrechen. Es scheint, eine Höhe von * einzustellen funktioniert nicht.
MainWindow.xaml
<Window x:Class="WpfItemsControlVirtualization.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="500" >
<Window.Resources>
<ResourceDictionary>
<!--Virtualised ItemsControl-->
<Style x:Key="ItemsControlVirtialisedStyle" TargetType="ItemsControl">
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Go" Click="ButtonBase_OnClick"/>
<Button Grid.Row="1" Content="Expand" Click="ButtonBase_OnClick2"/>
<Expander Grid.Row="2" >
<ItemsControl ItemsSource="{Binding Collection}" Style="{StaticResource ItemsControlVirtialisedStyle}" VirtualizingPanel.ScrollUnit="Pixel">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<!-- <RowDefinition Height="*"></RowDefinition> --> <!-- VIRTUALIZATION BREAK -->
<RowDefinition Height="500"></RowDefinition>
</Grid.RowDefinitions>
<ItemsControl ItemsSource="{Binding Collection}" Style="{StaticResource ItemsControlVirtialisedStyle}" VirtualizingPanel.ScrollUnit="Pixel">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Test}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander>
</Grid>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfItemsControlVirtualization
{
/// <summary>
/// Implements the INotifyPropertyChanged interface for data binding purposes.
/// </summary>
public abstract class ViewModelBase : INotifyPropertyChanged, INotifyPropertyChanging
{
#region Abstract
public void AlertPropertyChanging(string propertyName)
{
OnPropertyChanging(propertyName);
}
public void AlertPropertyChanged(string propertyName)
{
OnPropertyChanged(propertyName);
}
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected void OnPropertyChanging(string propertyName)
{
var handler = PropertyChanging;
if (handler != null) handler(this, new PropertyChangingEventArgs(propertyName));
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
OnPropertyChanging(propertyName);
field = value;
OnPropertyChanged(propertyName);
return true;
}
protected void Set(Action action, string propertyName = null)
{
OnPropertyChanging(propertyName);
if (action != null) action();
OnPropertyChanged(propertyName);
}
#endregion
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
#endregion Implementation of INotifyPropertyChanged
#region Implementation of INotifyPropertyChanging
public event PropertyChangingEventHandler PropertyChanging;
#endregion Implementation of INotifyPropertyChanging
}
public class MySubDataTest : ViewModelBase
{
public MySubDataTest()
{
}
public string Test
{
get { return "SubTest"; }
set { }
}
public bool IsExpanded
{
get { return m_IsExpanded; }
set { Set(ref m_IsExpanded, value); }
}
private bool m_IsExpanded = false;
}
public class MyDataTest : ViewModelBase
{
public MyDataTest()
{
int test = 1000;
for (int i = 0; i < test; i++)
{
Collection.Add(new MySubDataTest());
}
}
public string Test
{
get { return "Test"; }
set { }
}
public bool IsExpanded
{
get { return m_IsExpanded; }
set { Set(ref m_IsExpanded, value); }
}
private bool m_IsExpanded = false;
public ObservableCollection<MySubDataTest> Collection
{
get { return m_Collection; }
}
ObservableCollection<MySubDataTest> m_Collection = new ObservableCollection<MySubDataTest>();
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public ObservableCollection<MyDataTest> Collection
{
get { return m_Collection; }
}
ObservableCollection<MyDataTest> m_Collection = new ObservableCollection<MyDataTest>();
private void ButtonBase_OnClick(object _sender, RoutedEventArgs _e)
{
int count = 1;
for (var i = 0; i < count; i++)
{
Collection.Add(new MyDataTest());
}
DataContext = this;
}
private void ButtonBase_OnClick2(object _sender, RoutedEventArgs _e)
{
foreach (MyDataTest test in Collection)
{
foreach (MySubDataTest sub in test.Collection)
{
sub.IsExpanded = true;
}
test.IsExpanded = true;
}
}
}
}
Vielen Dank im Voraus.
Dies beantwortet meine Frage nicht, es gab ein Problem, das ich oben gelöst habe – Asheh
_Meine Frage ist, ist das möglich? _ Meine Antwort ist "Nein". ItemsControl virtualisiert nur ihre direkten Elemente, nicht potenzielle Elemente, die von verschachtelten ItemsControl enthalten sind. Ich bin mir nicht sicher, ob Sie das wirklich verstehen, aber es ist klar, was Sie von ItemsControl erwartet haben, aber ** das macht es nicht, mit Absicht **. – franssu