2016-04-18 9 views
3

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.

Antwort

-1

Es gibt keine echte Out-of-the-Box-Möglichkeit, dies zu tun. Die Art und Weise, wie ich es am Ende getan habe, war die vollständige Anpassung der Templates eines TreeView, da es die hierarchische Virtualisierung unterstützt.

Sie können dies zusammen mit DataTemplates verwenden, um dasselbe Ergebnis wie mit rekursiven ItemsTemplates zu erzielen, und es ist viel effizienter.

-1

Hier gibt es kein Problem. Die ItemTemplate Ihrer äußeren ItemsControl enthält eine ItemsControl selbst. In einem ItemsControl wird jedes Element entweder gerendert oder nicht. Die Virtualisierung kann dazu beitragen, nicht sichtbare Elemente nicht zu rendern, aber das erste Element ist teilweise sichtbar, daher ist es nicht für die Virtualisierung geeignet und wird vollständig mit unbegrenzter Höhe gerendert.

+0

Dies beantwortet meine Frage nicht, es gab ein Problem, das ich oben gelöst habe – Asheh

+0

_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

Verwandte Themen