【问题标题】:Asynchronous Call Best Practice异步调用最佳实践
【发布时间】:2010-11-10 00:26:05
【问题描述】:

我正在使用 vs.NET 2010 和 C# windows 窗体开发一个 windows 应用程序。这个应用程序有一个用户控件来查询服务(WCF 托管在 win 服务上),并且需要在不阻塞 UI 的情况下执行此操作。用户控件包含将显示该结果的网格。我认为我的情况是最常见的。我的问题是用 C# 可以做什么,以使以下代码运行更顺畅并具有更好的错误处理。我正在使用 MehtodInvoker,所以我可以避免为此调用编写两个单独的方法 - 等待 - 填充场景。

public void LoadData()
{
    StartWaitProgress(0);
    ThreadPool.QueueUserWorkItem(x =>
    {
        try
        {
            MyDocMail[] mails;
            var history = Program.NoxProxy.GetDocumentHistory(out mails, Program.MySessionId, docId);
            this.Invoke(new MethodInvoker(delegate()
            {
                this.SuspendLayout();
                gridVersions.Rows.Clear();
                foreach (var item in history)
                {
                    gridVersions.Rows.Add();
                    int RowIndex = gridVersions.RowCount - 1;
                    DataGridViewRow demoRow = gridVersions.Rows[RowIndex];
                    demoRow.Tag = item.Id;
                    if (gridVersions.RowCount == 1)
                    {
                        demoRow.Cells[0].Value = Properties.Resources.Document_16;
                    }
                    demoRow.Cells[1].Value = item.Title; 
                    demoRow.Cells[2].Value = item.Size.GetFileSize();
                    demoRow.Cells[3].Value = item.LastModified;
                    demoRow.Cells[4].Value = item.CheckoutBy;
                    demoRow.Cells[5].Value = item.Cotegory;
                }
                gridEmails.Rows.Clear();
                foreach (var item in mails)
                {
                    gridEmails.Rows.Add();
                    int RowIndex = gridEmails.RowCount - 1;
                    DataGridViewRow demoRow = gridEmails.Rows[RowIndex];
                    demoRow.Tag = item.Id;
                    demoRow.Cells[1].Value = item.From;
                    demoRow.Cells[2].Value = item.To;
                    demoRow.Cells[3].Value = item.Date;
                }
                this.ResumeLayout();
            }));
        }
        catch (Exception ex)
        {
            Program.PopError(ex);
            this.Invoke(new MethodInvoker(delegate() { this.Close(); })); 
        }
        finally { this.Invoke(new MethodInvoker(delegate() { StopWaitProgress(); })); }
    });
}

【问题讨论】:

    标签: c# winforms wcf asynchronous


    【解决方案1】:

    您的解决方案没有任何问题,尽管您可以使用BackgroundWorker 更轻松地完成它。

    BackgroundWorker 处理线程异常,在 WPF 窗口上调用 Invoke,并帮助进行进度报告和取消。更多示例here。

    附:未来的 C# 版本可能会使这变得更容易 - 查看Async CTP。

    【讨论】:

    • 您也可以使用 .NET 4 框架中的 Task 来清理它。
    • 我已经在 C# 2.0 中尝试过 BackgroundWorker 解决方案,但我没有看到任何优势,使用 BackgroundWorker 我必须将代码分成多个方法/事件。在我的应用程序中,有时我会在同一个表单中对 wcf 服务进行 10 次调用。为了加快这个调用,我必须同时进行它们(在 ThreadPool 上并行运行),这样会产生 10 个 BackgroundWorker 实例......上面的代码更紧凑,因为我可以为每个异步调用编写一个方法.
    • 请记住,您可以通过编程方式实例化 BackgroundWorker,并使用匿名方法或 lambda 表达式来处理事件(这通常是我所做的)。最佳解决方案取决于您的最终目标。您能否详细说明“更流畅且具有更好的错误处理能力”的含义?
    • 假设我有 10 个 BackgroundWorkers 用于我的异步作业,它们的行为会像 ThreadPool.QueueUserWorkItem 一样,还是会因为启动太多线程而导致 CPU 过载?
    • BackgroundWorker 使用线程池 - 所以是的,它们的行为类似于 ThreadPool.QueueUserWorkItem。
    猜你喜欢
    • 1970-01-01
    • 2019-01-29
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    • 2011-08-12
    • 2013-02-02
    • 2018-12-26
    • 2018-02-14
    相关资源
    最近更新 更多