开发者

IAsyncresult - polling without freezing the UI?

I've got a windows svc which is running asynchronously (I've edited the methods and their parameters to make them async), a little like: http://msdn.microsoft.com/en-us/library/ms731177.aspx

However, I call the task which I want to run asynchronously (the call to the service/server), and then update the UI (using ReportProgress() on the backgroundworker - all of this is happening in the dowork() method of a backgroundworker). However, I call the Endxxx method to get the results, but the problem is, shouldn't my 开发者_StackOverflow中文版code look like?

while (!asyncresult.IsCompleted) { // Do all UI updating etc here... }

// Call endXXX here.

However, this approach locks the UI. At the moment, my code is like so (and doesn't lock the UI):

 IAsyncResult res = null;

                try
                {

                    res = serviceX.BeginXXX(ResultCallBack, "");
                }
                catch (FaultException<ManagementException> managementEx)
                {
                    Logger.Error(managementEx.Detail.ToString());
                    MessageBox.Show("Could not add printer. See log.");
                }



                    InstallBackgoundWorker.ReportProgress(90);
                    InstallBackgoundWorker.ReportProgress(91);
                    InstallBackgoundWorker.ReportProgress(93);

                    InstallBackgoundWorker.ReportProgress(94);
                    InstallBackgoundWorker.ReportProgress(95);
                    InstallBackgoundWorker.ReportProgress(96);
                    InstallBackgoundWorker.ReportProgress(97);



                    if (res.IsCompleted)
                    {
                        ResultCallBack(res);
                    }
                    InstallBackgoundWorker.ReportProgress(100);

Is this correct? It seems wrong to me.


I'm not certain that you're using the async pattern correctly. It should look something like this:

void Start()
{
    System.IO.Stream s = ...;
    byte[] buf = ...;

    // start the IO.

    s.BeginRead(buf, 0, buf.Length, res =>
        {
            // this gets called when it's finished,
            // but you're in a different thread.

            int len = s.EndRead(res);

            // so you must call Dispatcher.Invoke
            // to get back to the UI thread.

            Dispatcher.Invoke((Action)delegate
                {
                    // perform UI updates here.
                });
        }, null);

    // the IO is started (and maybe finished) here,
    // but you probably don't need to put anything here.
}

Written with Stream because I don't know the signature of your object, but hopefully you get the idea! You need to process the completion of the operation in the callback you give it, not directly after you call the Begin method. You shouldn't need to poll the IsCompleted property.


No you should not take the first approach, since it defeats the objective of calling a method in an async fashion.

Second approach is also troublesome since

  • your progress reporting is arbitrary and unrealistic
  • even with 100% it does not guarantee that the work is done since at 100% it does not know if the work has been done.

There is no way to show a progress report for an async job unless async just provides it.

Solution is:

  • Show an indeterminate progress bar (also called spinner)
  • Report user of the result inside the callback

You must also be aware of the issues communicating with the UI thread from a background thread and using Invoke in Windows Forms and using Dispatcher in WPF.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜