Stefan P.
Stefan P.

Reputation: 9519

Asynchronous Call Best Practice

I am developing a windows application with vs.NET 2010 and C# windows forms. This app has an user control that queries a service(WCF hosted on win service) and needs to do this without blocking the UI. The user control contains a grid that will show that results. I think that my situation is most common. My question to you is what can be done with C# in order for the following code to run smoother and with a better error handling. I am using MehtodInvoker so I can avoid writeing two seprate methods for this call - wait - fill scenario.

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(); })); }
    });
}

Upvotes: 0

Views: 1112

Answers (1)

Joe Albahari
Joe Albahari

Reputation: 30994

There's nothing wrong with your solution, although you can accomplish it more easily with BackgroundWorker.

BackgroundWorker handles thread exceptions, calling Invoke on the WPF window, and helps with progress reporting and cancellation. More examples here.

P.S. Future versions of C# may make this even easier - check out the Async CTP.

Upvotes: 3

Related Questions