WPF ComboBox 绑定大集合的性能问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8198645/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:11:15  来源:igfitidea点击:

WPF ComboBox performance problems by binding a large collections

wpfdata-bindingcomboboxwpf-controls

提问by Alexey

I'm trying to bind a large collection to a ComboBox and I faced performance problems when opening ComboBox's popup. I searched internet and found that using VirtualizingStackPanel as a items panel template might help, but it helped only partially. If I bind a large collection to a ComboBox, I could open popup very quickly, that's ok, but if after that I bind another collection to a ComboBox and try to open popup again, it becomes very slow. Same is happening if you open popup for an empty ComboBox, then bind large collection and try to open popup again - it takes some seconds before popup opens.

我正在尝试将大型集合绑定到 ComboBox,但在打开 ComboBox 的弹出窗口时遇到了性能问题。我在互联网上搜索并发现使用 VirtualizingStackPanel 作为项目面板模板可能会有所帮助,但只是部分帮助。如果我将一个大集合绑定到一个 ComboBox,我可以非常快地打开弹出窗口,那没关系,但是如果之后我将另一个集合绑定到一个 ComboBox 并尝试再次打开弹出窗口,它会变得非常慢。如果您为空的 ComboBox 打开弹出窗口,然后绑定大集合并尝试再次打开弹出窗口,则会发生同样的情况 - 在弹出窗口打开之前需要几秒钟。

Here is the XAML:

这是 XAML:

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

and the sample code for binding to reproduce the problem:

以及用于绑定重现问题的示例代码:

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

I tried to make virtualizing stack panel to look like this:

我试图使虚拟化堆栈面板看起来像这样:

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

but it doesn't help, seems VirtualizationMode is ignored so popup opens very fast only first time and then, each time after binding changes, it's very slow.

但这无济于事,似乎 VirtualizationMode 被忽略,因此弹出窗口仅第一次打开非常快,然后,每次绑定更改后,它都非常慢。

UPDATE: I thought about not binding new collection every time, but bind an ObservableCollection once and then just changing its content. Same thing, as soon as content of collection changes, opening a popup still takes several seconds :(

更新:我想不是每次都绑定新集合,而是绑定一个 ObservableCollection 一次,然后只是更改其内容。同样的事情,只要收藏的内容发生变化,打开弹出窗口仍然需要几秒钟:(

回答by Miguel

According to this blog: http://vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx

根据这个博客:http: //vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx

I've tested it with this code:

我用这个代码测试过它:

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

It works fine for first time and next times. It's not necessary to code these lines:

第一次和下次都可以正常工作。没有必要对这些行进行编码:

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

I hope this helps you.

我希望这可以帮助你。

回答by jonas

I had the issue with slow performance as well. But I had created a class that inherited form Combobox, therefor I would like to do this programmatically. So here is that solution for other googlers out there.

我也遇到了性能缓慢的问题。但是我创建了一个继承 Combobox 形式的类,因此我想以编程方式执行此操作。所以这是其他谷歌员工的解决方案。

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

回答by Phillip

I just ran into this issue as well. I'm using this code in a custom combo box with a style template. When I ran my code in VS debugging mode the virtualization did not work properly. Once I ran it outside of debugging I can switch the content of the ObservableCollection without locking the UI up. It also might help if you set a max height and max width.

我也刚遇到这个问题。我在带有样式模板的自定义组合框中使用此代码。当我在 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>