2016-04-18 11 views
3

最近仮想化の問題に遭遇し、以下のコードに絞り込んだ。ItemsControl内で高さが*のItemsControlを仮想化

次のスニペットで仮想化が機能しないのは、子が特定の高さを持たないためです。だから私の推測は、それが永遠に拡大し、仮想化が破綻するということです。

子を特定の高さに設定すると問題が解決されますが、スクロールバーが1つの場合はインターフェイスが2つの目障りなスクロールバーになり、アイテムコントロールによって生成されたコンテンツ全体をスクロールします。

私の質問は、これは可能ですか?もしそうなら、私はこれをどのように達成できますか?どうやら、子供は仮想化を破ることなく、自分自身のサイズを計算する必要があります。 *の高さを設定するとうまくいかないようです。

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; 
      } 
     } 
    } 
} 

事前にありがとうございます。

答えて

-1

これを行うには実際の方法はありません。私が最終的にやったやり方は、階層化された仮想化をサポートするので、TreeViewのテンプレートを完全にカスタマイズすることでした。

これをDataTemplatesと一緒に使用すると、再帰的ItemsTemplatesと同じ結果を得ることができ、その効率ははるかに高くなります。

-1

ここに問題はありません。外側ItemsControlItemTemplateにはItemsControlが含まれています。 ItemsControlでは、各要素はレンダリングされるかどうかにかかわらずレンダリングされます。仮想化は目に見えない要素のレンダリングには役立ちませんが、最初の要素は部分的に見えるため、仮想化には適しておらず、完全に無限の高さでレンダリングされます。

+0

これは私が上で解決した問題があった私の質問に答えない – Asheh

+0

_私の質問は、これは可能ですか?_私の答えは "いいえ"です。 ItemsControlは、直接項目のみを仮想化し、ネストされたItemsControlに含まれる可能性のある項目は仮想化しません。私はあなたがこれをかなり理解しているかどうかは確かではありませんが、あなたがItemsControlが何を期待しているのかはっきりしていますが、**これは設計によって**できません。 – franssu

関連する問題