向 ListBox 添加许多项目,同时保持 UI 响应

Posted

技术标签:

【中文标题】向 ListBox 添加许多项目,同时保持 UI 响应【英文标题】:Add many items to ListBox while keeping the UI resposive 【发布时间】:2021-07-21 20:00:41 【问题描述】:

我正在尝试使用大量数据更新 ListBox 并同时保持 UI 响应。

这是我用来实现此目的的代码,遍历 10000 个项目,将它们收集到 100 个项目的批次中,然后一次性插入这 100 个项目,这样我就可以避免每次添加单个项目时更新 UI,但不幸的是,代码不起作用,只有在将所有 10000 个项目实际添加到 ListBox 后,才会更新 UI。

public partial class Form1 : Form

    private SynchronizationContext synchronizationContext;

    public Form1()
    
        InitializeComponent();
    

    private async void button1_Click(object sender, EventArgs e)
    
        synchronizationContext = SynchronizationContext.Current;

        await Task.Run(() =>
        
            ConcurrentDictionary<int, int> batch = new ConcurrentDictionary<int, int>();
            int count = 0;
            for (var i = 0; i <= 10000; i++)
            
                batch[i] = i;
                count++;
                if (count == 100)
                
                    count = 0;
                    UpdateUI(batch);
                    batch = new ConcurrentDictionary<int, int>();
                

                
            
        );
    

    private void UpdateUI(ConcurrentDictionary<int, int> items)
    
        synchronizationContext.Post(o =>
        
            listBox1.SuspendLayout();
            foreach (var item in items)
            
                listBox1.Items.Add(item.Value);
            

            listBox1.ResumeLayout();

        , null);
    

【问题讨论】:

您可以用BeginInvoke() 替换整个 SynchronizationContext 和 Post() 方法调用(因为所有方法都在同一个 Form 类中工作。否则,传递一个 Progress<T> 委托:这是一个简化的方法将 Post() 发送到 SynchronizationContext 而不显式捕获它,IProgress&lt;T&gt; 委托会为您执行此操作)。那么,你不需要SuspendLayout()/ResumeLayout()(无关),而是BeginUpdate()/EndUpdate() 也许这会有所帮助:***.com/questions/2341731/… a) AddRange b) 如果你关心 UI,为什么要添加这么多项目?? 【参考方案1】:

您不需要多线程方法来更新 UI。您只需使用ListBox.BeginUpdateListBox.EndUpdate 方法在批量插入期间暂停ListBox 的绘制:

private void button1_Click(object sender, EventArgs e)

    listBox1.BeginUpdate();
    for (var i = 1; i <= 10000; i++)
    
        listBox1.Items.Add(i);
    
    listBox1.EndUpdate();

Control.SuspendLayoutControl.ResumeLayout 方法用于在灵活容器中动态添加控件,并且希望在添加每个新控件时防止控件跳来跳去。

【讨论】:

那么只需:listBox1.DataSource = Enumerable.Range(0, 10000).Select(i =&gt; i).ToArray();。 -- 确实,OP 没有指定是否调用阻塞方法来获取此项目集合,但可能是这种情况。不过,OP 应该澄清,数据源很重要

以上是关于向 ListBox 添加许多项目,同时保持 UI 响应的主要内容,如果未能解决你的问题,请参考以下文章

C# WPF 如何在向 Stackpanel 添加许多 UI 元素时保持应用程序响应

在列表框项目之间添加文本

WPF:如何在调整大小后保持 ListBox SelectedItem 可见?

是否有在保持颜色的同时向 ggplot 饼图添加模式的功能?

怎样向DEV控件RadioGroup添加项及listbox项的添加删除

如何在 ui-router angularjs 中保持父级相同的同时仅更改子级 ui-view?