c# - 使用 BackgroundWorker 更新 UI 而不会卡住......?

标签 c# multithreading user-interface delegates backgroundworker

我有以下代码用于从后台线程填充 ListView(DoWork 调用 PopulateThread 方法):

delegate void PopulateThreadCallBack(DoWorkEventArgs e);
private void PopulateThread(DoWorkEventArgs e)
{

    if (this.InvokeRequired)
    {
        PopulateThreadCallBack d = new PopulateThreadCallBack(this.PopulateThread);
        this.Invoke(d, new object[] { e });
    }
    else
    {

        // Ensure there is some data
        if (this.DataCollection == null)
        {
            return;
        }

        this.Hide();

        // Filter the collection based on the filters
        List<ServiceCallEntity> resultCollection = this.ApplyFilter();

        // Get the current Ids
        List<Guid> previousIdList = this.GetUniqueIdList(listView);
        List<Guid> usedIdList = new List<Guid>();

        foreach (ServiceCallEntity record in resultCollection)
        {

            if (e.Cancel)
            {
                this.Show();
                return;
            }
            else
            {

                // Get the top level entities
                UserEntity userEntity = IvdSession.Instance.Collection.GetEngineerEntity(record.UserId);
                AssetEntity assetEntity = IvdSession.Instance.Collection.GetAssetEntity(record.AssetId);
                SiteEntity siteEntity = IvdSession.Instance.Collection.GetSiteEntity(record.SiteId);
                FaultEntity faultEntity = IvdSession.Instance.Collection.GetFaultEntity(record.FaultId);

                if (siteEntity == null || userEntity == null || faultEntity == null)
                {
                    continue;
                }
                else
                {

                    // Get the linked entities
                    RegionEntity regionEntity = IvdSession.Instance.Collection.GetRegionEntity(siteEntity.RegionId);
                    StatusEntity statusEntity = IvdSession.Instance.Collection.GetStatusEntity(record.ServiceCallStatus.StatusId);

                    ListViewItem item = new ListViewItem(siteEntity.SiteName);
                    item.SubItems.Add(siteEntity.Address);
                    item.Tag = record;

                    item.SubItems.Add(regionEntity.Description);

                    // Handle if an Asset is involved
                    if (record.AssetId > 0)
                        item.SubItems.Add(assetEntity.AssetDisplay);
                    else
                        item.SubItems.Add("N/A");

                    item.SubItems.Add(faultEntity.Description);
                    item.SubItems.Add(userEntity.UserDisplay);

                    item.SubItems.Add("TODO: Claimed By");
                    item.SubItems.Add(record.DateTimeStamp.ToString());

                    IvdColourHelper.SetListViewItemColour(item, false);
                    this.PopulateItem(item, ref usedIdList);

                }

            }

        }

        // Clean up the grid
        this.CleanListView(previousIdList, usedIdList);

        // Only autosize when allowed and when there are some items in the ListView
        if (this.AllowAutoSize && listView.Items.Count > 0)
        {
            rsListView.AutoSizeColumns(listView);
            this.AllowAutoSize = false;
        }

        this.Show();

    }

}

不幸的是,这会导致 UI 在 foreach 中卡住...有什么方法可以在不卡住主 UI 的情况下更新/填充 ListView 吗?

最佳答案

A) 您可能不需要使用 this.Invoke,而是使用 this.BeginInvoke。 Invoke 阻塞当前线程。

B) 你不需要定义你自己的委托(delegate)你可以使用 MethodInvoker

if(this.InvokeRequired) {
  this.BeginInvoke(new MethodInvoker(() => PopulateThread(e)));
  return;
}

它更干净:)

关于c# - 使用 BackgroundWorker 更新 UI 而不会卡住......?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/988267/

相关文章:

javascript - toggleClass 缓动仅适用于缓出

c# - 使用更多方法提高C#中Parallel.For的性能

Ruby 线程 : how to catch an exception without calling . 加入?

c++ - OOP 游戏菜单系统开发概念化

java - 条件变量和锁的使用

c++ - 获取线程 ID 在性能方面是否昂贵?

java - 组件未对准

c# - 当我向数组添加某些内容时,它不会向列表添加任何内容

c# - 在主线程中运行代码

c# - 使用 RegEx 去除文件名中的多个句点