web-dev-qa-db-ja.com

大きなコレクションをバインドすることによるWPF ComboBoxのパフォーマンスの問題

大きなコレクションをComboBoxにバインドしようとしていますが、ComboBoxのポップアップを開くときにパフォーマンスの問題が発生しました。インターネットを検索したところ、VirtualizingStackPanelを項目パネルテンプレートとして使用すると効果があるかもしれませんが、効果は部分的にしかわかりませんでした。大きなコレクションをComboBoxにバインドすると、ポップアップを非常に速く開くことができますが、その後、別のコレクションをComboBoxにバインドして、もう一度ポップアップを開こうとすると、非常に遅くなります。空のComboBoxのポップアップを開き、大きなコレクションをバインドしてもう一度ポップアップを開こうとすると、同じことが起こります-ポップアップが開くまでに数秒かかります。

XAMLは次のとおりです。

<ComboBox Name="cbBlah">
    <ComboBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ComboBox.ItemsPanel>
</ComboBox>

問題を再現するためのバインドのサンプルコード:

var list = new List<string>();
for (var i = 0; i < new Random().Next(9000, 10000); i++)
    list.Add(i.ToString());
cbBlah.ItemsSource = list;

仮想化スタックパネルを次のようにしてみました。

<VirtualizingStackPanel VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" />

しかし、それは役に立たないようです。VirtualizationModeは無視されているようです。そのため、ポップアップは最初は非常に速く開き、その後、変更をバインドするたびに非常に遅くなります。

[〜#〜] update [〜#〜]:毎回新しいコレクションをバインドするのではなく、ObservableCollectionを1回バインドして、そのコンテンツを変更することを考えました。同じことですが、コレクションの内容が変更されても、ポップアップを開くのに数秒かかります:(

48
Alexey

このブログによると: http://vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx

私はこのコードでそれをテストしました:

<ComboBox Name="cbBlah" ItemsSource="{Binding}">
    <ComboBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ComboBox.ItemsPanel>
</ComboBox>

初回と次回は正常に動作します。次の行をコーディングする必要はありません。

<VirtualizingStackPanel VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" />

これがお役に立てば幸いです。

101
Miguel

パフォーマンスが遅いという問題もありました。しかし、Comboboxから継承したクラスを作成したので、これをプログラムで実行したいと思います。だからここに他のグーグルのためのその解決策があります。

ItemsPanel = new ItemsPanelTemplate();
var stackPanelTemplate = new FrameworkElementFactory(typeof (VirtualizingStackPanel));
ItemsPanel.VisualTree = stackPanelTemplate;
9
jonas

私もこの問題に遭遇しました。このコードを、スタイルテンプレートのあるカスタムコンボボックスで使用しています。 VSデバッグモードでコードを実行すると、仮想化が正しく機能しませんでした。デバッグ以外で実行すると、UIをロックすることなくObservableCollectionのコンテンツを切り替えることができます。最大の高さと最大の幅を設定する場合にも役立ちます。

<Setter Property="ScrollViewer.CanContentScroll" Value="True"/> 
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
<Popup>
    <Border/>
    <ScrollViewer>
      <VirtualizingStackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained"/>
    </ScrollViewer> 
  </Grid>
</Popup>
0
Phillip