none
ListBox.GroupStyleのTemplate定義でScrollViewerを用いている場合に、仮想化パネルを適用すると例外が発生する RRS feed

  • 質問

  • ListBoxでGroup化している場合に、GroupStyleでTemplateを定義し、そこで「ScrollViewer」を用いている場合に、

    ListBoxの「ItemsPanel」で仮想化パネル「VirtualizingStackPanel」を適用すると以下の例外が発生します。
    -------------------------------------------------------------------------------------------------
    System.NullReferenceException
      HResult=0x80004003
      Message=オブジェクト参照がオブジェクト インスタンスに設定されていません。
      Source=PresentationFramework
      スタック トレース:
       場所 System.Windows.Controls.VirtualizingStackPanel.GetAreContainersUniformlySized(IContainItemStorage itemStorageProvider, Object item)
       場所 System.Windows.Controls.VirtualizingStackPanel.MeasureOverrideImpl(Size constraint, Nullable`1& lastPageSafeOffset, List`1& previouslyMeasuredOffsets, Nullable`1& lastPagePixelSize, Boolean remeasure)
       場所 System.Windows.Controls.VirtualizingStackPanel.MeasureOverride(Size constraint)
       場所 System.Windows.FrameworkElement.MeasureCore(Size availableSize)
    ・・・
    -------------------------------------------------------------------------------------------------
    なぜこの例外が起こるのかがわからなく、困っております。
    例外を発生させることなく、仮想化を適用したいのですが、解決法をお教えいただけると幸いです。
    以下サンプルコード:
    (簡略化のためGroupStyle.Panelの方はStackPanelを用いているので、以下のサンプルコードではScrollViewerが意味のないものになっていますが、ゆくゆくは個々のGroupの高さは一定にする予定です)

    <Window x:Class="Sample.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:Sample"
            Title="MainWindow" Height="350" Width="525">
        <ListBox x:Name="listBox"
                ScrollViewer.VerticalScrollBarVisibility="Auto"
                ScrollViewer.HorizontalScrollBarVisibility="Auto"
                VirtualizingPanel.IsVirtualizing="True"
                VirtualizingPanel.IsVirtualizingWhenGrouping="True"
                VirtualizingPanel.ScrollUnit="Item"
                ScrollViewer.CanContentScroll="True"
                VirtualizingPanel.IsContainerVirtualizable="True"
                VirtualizingPanel.VirtualizationMode="Standard">
            <ListBox.GroupStyle>
                <GroupStyle>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Template" >
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                        <ScrollViewer CanContentScroll="True">
                                            <ItemsPresenter ScrollViewer.CanContentScroll="True"/>
                                        </ScrollViewer>
    
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                    <GroupStyle.Panel>
                        <ItemsPanelTemplate>
                            <StackPanel/>
                        </ItemsPanelTemplate>
                    </GroupStyle.Panel>
                </GroupStyle>
            </ListBox.GroupStyle>
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel/>
                    <!--<StackPanel/>--><!--←←仮想化パネルではない場合は表示可能-->
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListBox>
    </Window>
        public partial class MainWindow : Window
        {
            private readonly Random RandomObject = new Random();
    
            private ObservableCollection<Person> people = new ObservableCollection<Person>();
    
            public MainWindow()
            {
                InitializeComponent();
    
                var source = new CollectionViewSource();
                source.GroupDescriptions.Add(new System.Windows.Data.PropertyGroupDescription("Category"));
                if (source != null)
                {
                    source.Source = people;
                }
                listBox.ItemsSource = source.View;
    
                foreach (var _ in Enumerable.Range(1, 1000))
                {
                    this.people.Add(
                        new Person("No " + (this.people.Count + 1) + "Person", this.RandomObject.Next(100)));
                }
            }
        }
        public class Person
        {
            public Person(string _name, int _category)
            {
                Name = _name;
                Category = _category;
            }
    public string Name { get; set; } public int Category { get; set; } public override string ToString() { return string.Format("{0}, Category:{1}", this.Name, this.Category); } }






























    • 編集済み yj0529 2019年9月6日 5:49
    2019年9月6日 5:33

回答

  • バグか仕様かは判らないけど、内側になるScrollViewerのCanContentScrollが干渉しているっぽい

    <GroupStyle.ContainerStyle>
        <Style TargetType="{x:Type GroupItem}">
            <Setter Property="Template" >
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type GroupItem}">
                        <!-- <ScrollViewer CanContentScroll="True"> -->
                        <ScrollViewer >
                            <ItemsPresenter />
                        </ScrollViewer>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </GroupStyle.ContainerStyle>


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク yj0529 2019年9月19日 23:47
    2019年9月6日 10:05
  • Microsoftによると本件は、VirtualizingStackPanelの不具合のようです。

    app.configに<add key="IsVirtualizingStackPanel_45Compatible" value="true"/>の設定を追加して、.NET Framework4.5互換で動くようにすると解消しました。

    #以下と同じ対応になります。

    https://blogs.msdn.microsoft.com/japan_platform_sdkwindows_sdk_support_team_blog/2018/03/30/treeview-stackoverflowexception-wpf-47-crash/

    • 回答としてマーク yj0529 2019年9月19日 23:47
    2019年9月19日 23:46

すべての返信

  • バグか仕様かは判らないけど、内側になるScrollViewerのCanContentScrollが干渉しているっぽい

    <GroupStyle.ContainerStyle>
        <Style TargetType="{x:Type GroupItem}">
            <Setter Property="Template" >
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type GroupItem}">
                        <!-- <ScrollViewer CanContentScroll="True"> -->
                        <ScrollViewer >
                            <ItemsPresenter />
                        </ScrollViewer>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </GroupStyle.ContainerStyle>


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク yj0529 2019年9月19日 23:47
    2019年9月6日 10:05
  • gekka様

    ご返信ありがとございます。
    CanContentScroll=falseにすると、仮想化自体が無効になってしまうようなので、
    https://docs.microsoft.com/ja-jp/dotnet/framework/wpf/advanced/optimizing-performance-controls

    結果的に仮想化自体が影響していそうですよね...

    2019年9月9日 4:54
  • yj0529さん、こんにちは。フォーラムオペレーターのHarukaです。
    MSDNフォーラムにご投稿くださいましてありがとうございます。

    ご質問いただいた件ですが、その後いかがでしょうか。問題は解決しましたか。
    追加でご確認いただいたことなどあれば、追記いただくことで回答がつきやすくなります。

    どうぞよろしくお願いします。


    MSDN/ TechNet Community Support Haruka

    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、
    ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年9月12日 8:23
    モデレータ
  • Microsoftによると本件は、VirtualizingStackPanelの不具合のようです。

    app.configに<add key="IsVirtualizingStackPanel_45Compatible" value="true"/>の設定を追加して、.NET Framework4.5互換で動くようにすると解消しました。

    #以下と同じ対応になります。

    https://blogs.msdn.microsoft.com/japan_platform_sdkwindows_sdk_support_team_blog/2018/03/30/treeview-stackoverflowexception-wpf-47-crash/

    • 回答としてマーク yj0529 2019年9月19日 23:47
    2019年9月19日 23:46