PDA开发系列:BackgroundWorker

     在.net compact framework中,没有BackgroundWorker,应该会让我们这些用惯了BackgroundWorker的人感到非常的不便。BackgroundWorker可以非常方便解决线程和控件之间的互操作问题,做出界面运行非常流畅的引用程序。(该组件因wince的某些特性,不能解决根本问题,建议还是用线程来解决。)

    在反编译了.net framework的BackgroundWorker后,发现基本上95%以上的代码都可以直接COPY过来,唯一存在问题的就是下面这段代码:

        if (this.asyncOperation != null)
        {
            this.asyncOperation.Post(this.progressReporter, arg);
        }
        else
        {
            this.progressReporter(arg);
        }

这段代实际上要做的事情是这样的:如果执行该方法的线程和控件所在的线程不是同一个线程,就把该委托交给控件所在的线程去执行,否则就直接执行,为了实现这个操作,我做了如下的改动,在构造函数中,我这样写:

public BackgroundWorker()
{
    this.threadStart = new WorkerThreadStartDelegate(this.WorkerThreadStart);
    this.operationCompleted = new SendOrPostCallback(this.AsyncOperationCompleted);
    this.progressReporter = new SendOrPostCallback(this.ProgressReporter);
    this.Handler = Thread.CurrentThread.ManagedThreadId;
}

所以,上面的代码我做了如下的改写:

if (Thread.CurrentThread.ManagedThreadId!= this.Handler)
{
    Post(this.progressReporter, arg);
}
else
{
    this.progressReporter(arg);
}

 

Post方法的代码如下:

public virtual void Post(SendOrPostCallback d, object state)
{
    if (d != null && controlToSendTo != null)
    {
        controlToSendTo.Invoke(d, state);
    }
}

controlToSendTo 是调用该BackgroundWorker得用户控件。该BackgroundWorker得所有代码是这样的:

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace ZFB.PDA.Dao
{
    public class BackgroundWorker : Component
    {
        private bool canCancelWorker;
        private bool cancellationPending;
        private static readonly object doWorkKey = new object();
        private bool isRunning;
        private readonly SendOrPostCallback operationCompleted;
        private static readonly object progressChangedKey = new object();
        private readonly SendOrPostCallback progressReporter;
        private static readonly object runWorkerCompletedKey = new object();
        private readonly WorkerThreadStartDelegate threadStart;
        private readonly int Handler = 0;
        private Control controlToSendTo = null;


        /// <summary>
        /// 开始后台任务
        /// </summary>
        public event DoWorkEventHandler DoWork
        {
            add
            {
                base.Events.AddHandler(doWorkKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(doWorkKey, value);
            }
        }

        /// <summary>
        /// 后台任务执行的进度
        /// </summary>
        public event ProgressChangedEventHandler ProgressChanged
        {
            add
            {
                base.Events.AddHandler(progressChangedKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(progressChangedKey, value);
            }
        }

        /// <summary>
        /// 后台任务完成
        /// </summary>
        public event RunWorkerCompletedEventHandler RunWorkerCompleted
        {
            add
            {
                base.Events.AddHandler(runWorkerCompletedKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(runWorkerCompletedKey, value);
            }
        }

        public BackgroundWorker()
        {
            this.threadStart = new WorkerThreadStartDelegate(this.WorkerThreadStart);
            this.operationCompleted = new SendOrPostCallback(this.AsyncOperationCompleted);
            this.progressReporter = new SendOrPostCallback(this.ProgressReporter);
            this.Handler = Thread.CurrentThread.ManagedThreadId;
        }

        private void AsyncOperationCompleted(object arg)
        {
            this.isRunning = false;
            this.cancellationPending = false;
            this.OnRunWorkerCompleted((RunWorkerCompletedEventArgs)arg);
        }

        public void CancelAsync()
        {
            this.cancellationPending = true;
        }

        protected virtual void OnDoWork(DoWorkEventArgs e)
        {
            DoWorkEventHandler handler = (DoWorkEventHandler)base.Events[doWorkKey];
            if (handler != null)
            {
                handler(this, e);
            }
        }

        protected virtual void OnProgressChanged(ProgressChangedEventArgs e)
        {
            ProgressChangedEventHandler handler = (ProgressChangedEventHandler)base.Events[progressChangedKey];
            if (handler != null)
            {
                handler(this, e);
            }
        }

        protected virtual void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
        {
            RunWorkerCompletedEventHandler handler = (RunWorkerCompletedEventHandler)base.Events[runWorkerCompletedKey];
            if (handler != null)
            {
                handler(this, e);
            }
        }

        private void ProgressReporter(object arg)
        {
            this.OnProgressChanged((ProgressChangedEventArgs)arg);
        }

        public void ReportProgress(int percentProgress)
        {
            this.ReportProgress(percentProgress, null);
        }

        public void ReportProgress(int percentProgress, object userState)
        {
            ProgressChangedEventArgs arg = new ProgressChangedEventArgs(percentProgress, userState);
            if (Thread.CurrentThread.ManagedThreadId!= this.Handler)
            {
                Post(this.progressReporter, arg);
            }
            else
            {
                this.progressReporter(arg);
            }
        }

        public void RunWorkerAsync(Control ctl)
        {
            this.RunWorkerAsync(ctl,null);
        }

        public void RunWorkerAsync(Control ctl,object argument)
        {
            if (this.isRunning)
            {
                throw new InvalidOperationException("BackgroundWorker_WorkerAlreadyRunning");
            }
            if (ctl == null)
            {
                throw new Exception();
            }
            controlToSendTo = ctl;
            this.isRunning = true;
            this.cancellationPending = false;
            this.threadStart.Invoke(argument);
        }

        private void WorkerThreadStart(object argument)
        {
            object result = null;
            Exception error = null;
            bool cancelled = false;
            try
            {
                DoWorkEventArgs e = new DoWorkEventArgs(argument);
                this.OnDoWork(e);
                if (e.Cancel)
                {
                    cancelled = true;
                }
                else
                {
                    result = e.Result;
                }
            }
            catch (Exception exception2)
            {
                error = exception2;
            }
            RunWorkerCompletedEventArgs arg = new RunWorkerCompletedEventArgs(result, error, cancelled);
            if (Thread.CurrentThread.ManagedThreadId != this.Handler)
            {
                Post(this.operationCompleted, arg);
            }
            else
            {
                this.operationCompleted(arg);
            }
        }

        public bool CancellationPending
        {
            get
            {
                return this.cancellationPending;
            }
        }

        public bool IsBusy
        {
            get
            {
                return this.isRunning;
            }
        }

        public bool WorkerSupportsCancellation
        {
            get
            {
                return this.canCancelWorker;
            }
            set
            {
                this.canCancelWorker = value;
            }
        }

        public virtual void Post(SendOrPostCallback d, object state)
        {
            if (d != null && controlToSendTo != null)
            {
                controlToSendTo.Invoke(d, state);
            }
        }

        private delegate void WorkerThreadStartDelegate(object argument);
        public delegate void SendOrPostCallback(object state);
    }

}

 

 

    如果大家有更好的办法,希望大家给我留言。。。

代码下载:BackgroundWorker

posted @ 2010-10-27 20:51  HOH  阅读(1024)  评论(8编辑  收藏  举报