【问题标题】:Losing UI functionality while using the Background Worker使用后台工作器时丢失 UI 功能
【发布时间】:2015-08-05 09:44:06
【问题描述】:

我对使用不同的线程和使用BackgroundWorker 很陌生,所以我还没有完全理解所有内容。我已经发布了我从下面程序的客户端获得的所有编码。

问题是,即使我使用 BackgroundWorker,当我从 WCF 服务加载数据时,我仍然会失去所有 UI 的功能到我的 WPF 客户端应用程序。加载数据大约需要 2-3 分钟(大约 +- 1500 行数据),因此用户体验非常糟糕。

在将数据加载到datagrid 时,我可能缺少什么明显的东西来使 UI 正常工作?任何建议将不胜感激,谢谢! :)

更新代码:

public partial class pgSysproStock : Window
{
    public pgSysproStock()
    {
        InitializeComponent();
        SysproStock.WindowState = WindowState.Normal;
        dgSysproStock.IsEnabled = false;

        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.WorkerReportsProgress = true;
        worker.ProgressChanged += worker_ProgressChanged;
        worker.RunWorkerAsync();
    }

    private readonly BackgroundWorker worker = new BackgroundWorker();

    private async void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        using (TruckServiceClient TSC = new TruckServiceClient())
        {
            List<AllStock> allStock = new List<AllStock>();
            this.Dispatcher.Invoke((Action)(() =>
            {
                prgStockProgress.Visibility = Visibility.Visible;
            }));
            foreach (var item in await TSC.GetSysproStockAsync())
                allStock.Add(new AllStock
                {
                    Id = item.Id,
                    StockCode = item.StockCode,
                    Description = item.Description,
                    ConvFactAltUom = item.ConvFactAltUom,
                    ConvMulDiv = item.ConvMulDiv,
                    ConvFactOthUom = item.ConvFactOthUom,
                    MulDiv = item.MulDiv,
                    Mass = item.Mass,
                    Updated_Supplier = item.Updated_Supplier,
                    CycleCount = item.CycleCount,
                    ProductClass = item.ProductClass.ToString(),
                    UnitCost = item.UnitCost,
                    Discount = item.Discount,
                    Warehouse = item.Warehouse,
                    MinimumStock = item.MinimumStock,
                    MaximumStock = item.MaximumStock,
                    StockForNow = item.StockForNow,
                    CoilWidth = item.CoilWidth,
                    SheetCoilLength = item.SheetCoilLength,
                    MaterialThickness = item.MaterialThickness
                });
            e.Result = allStock.ToArray();
        }
    }

    private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.prgStockProgress.Value = e.ProgressPercentage;
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {            
        dgSysproStock.ItemsSource = (AllStock[])e.Result;
        dgSysproStock.IsEnabled = true;
    }
}

编辑:我还从我的编码方法中删除了asyncawait,但数据似乎仍然没有通过。

我在此处添加了一个断点foreach (var item in await TSC.GetSysproStockAsync()),但我无法通过TSC.GetSysproStock()) 代码。为什么要这样做?

【问题讨论】:

  • 这是阻止您的 UI 的操作:dgSysproStock.ItemsSource = (allStock.ToArray());
  • 您不能将 async/await 与后台工作人员混合使用。 worker_DoWork 不能是异步的。我想说扔掉 BGW 并单独使用 async await。
  • 乍一看,在 BackgroundWorker 中使用 async/await 似乎是错误的。
  • @Sriram Sakthivel - 感谢您的评论! :) 如果我删除 BackgroundWorker 我将无法使用我的 UI,因为当我从 WCF 服务加载数据时它会被禁用。
  • 如果你正确使用了 async/await,就不需要 BackgroundWorker。 await 关键字导致方法执行被拆分到多个线程中,方法的其余部分充当回调。

标签: c# wpf multithreading wcf backgroundworker


【解决方案1】:

正确使用 async/await:

    public pgSysproStock()
    {
        InitializeComponent();
        SysproStock.WindowState = WindowState.Normal;

        this.UpdateStockAsync();
    }

    private async void UpdateStockAsync()
    {
        dgSysproStock.IsEnabled = false;

        using (TruckServiceClient TSC = new TruckServiceClient())
        {
            var allStock = await TSC.GetSysproStockAsync().ToArray();

            dgSysproStock.ItemsSource = allStock.Select(item =>
                        new AllStock
                            {
                                Id = item.Id,
                                StockCode = item.StockCode,
                                Description = item.Description,
                                ConvFactAltUom = item.ConvFactAltUom,
                                ConvMulDiv = item.ConvMulDiv,
                                ConvFactOthUom = item.ConvFactOthUom,
                                MulDiv = item.MulDiv,
                                Mass = item.Mass,
                                Updated_Supplier = item.Updated_Supplier,
                                CycleCount = item.CycleCount,
                                ProductClass = item.ProductClass.ToString(),
                                UnitCost = item.UnitCost,
                                Discount = item.Discount,
                                Warehouse = item.Warehouse,
                                MinimumStock = item.MinimumStock,
                                MaximumStock = item.MaximumStock,
                                StockForNow = item.StockForNow,
                                CoilWidth = item.CoilWidth,
                                SheetCoilLength = item.SheetCoilLength,
                                MaterialThickness = item.MaterialThickness
                        }).ToArray();

        dgSysproStock.IsEnabled = true;
    }
}

【讨论】:

  • 再次感谢 Glen 的第二个回答。使用您提供的新编码可以很好地加载数据,但我回到了所有 UI 仍然被禁用/无响应的第一格:(
  • 但感谢您尝试帮助我。 ;) 在我做了一些研究之后,我会在一段时间内提出一个新问题。
  • 我认为问题可能是 GetSysproStockAsync 使用 yield 关键字返回一个迭代器。尝试在我更新的答案中添加 .ToArray() ,看看这是否有帮助。
  • 嗨,格伦。 var allStock = await TSC.GetSysproStockAsync().ToArray(); 给了我错误:不包含 'ToArray' 的定义并且没有扩展方法 'ToArray'
  • 您可能需要添加“使用 System.Linq;”到代码文件
【解决方案2】:

BackgroundWorker 不应该这样使用。尝试将数据传递给 RunWorkerCompleted 事件处理程序并从那里更新 UI。

删除这个:

this.Dispatcher.Invoke((Action)(() =>
{
    dgSysproStock.ItemsSource = (allStock.ToArray());
    dgSysproStock.IsEnabled = true;
}));

在 DoWork 事件处理程序中,将 Result 设置为您的数据:

e.Result = allStock.ToArray();

然后在 RunWorkerCompleted 事件处理程序中:

dgSysproStock.ItemsSource = (AllSTock[])e.Result;
dgSysproStock.IsEnabled = true;

【讨论】:

  • 感谢 Glen 的回答和努力。 :D 我已经按照你的建议更新了代码,现在我可以使用我所有的 UI 元素(谢谢),但现在由于某种原因,数据似乎没有加载到我的数据网格中。问题可能出在我的 DoWork 活动结束时的 e.Result = allStock.ToArray(); 上吗?
猜你喜欢
  • 2018-10-13
  • 2011-07-27
  • 2023-02-04
  • 1970-01-01
  • 2012-06-07
  • 2017-02-12
  • 1970-01-01
  • 2011-07-18
  • 2022-01-23
相关资源
最近更新 更多