/// <summary>
 /// Raises the DoWork event.
 /// </summary>
 /// <param name="e">A <see cref="QueuedWorkerDoWorkEventArgs"/> that contains event data.</param>
 protected virtual void OnDoWork(QueuedWorkerDoWorkEventArgs e)
 {
     if (DoWork != null)
     {
         DoWork(this, e);
     }
 }
        /// <summary>
        /// Used by the worker thread to process items.
        /// </summary>
        private void Run()
        {
            while (!Stopping)
            {
                lock (lockObject)
                {
                    // Wait until we have pending work items
                    if (IsWorkQueueEmpty())
                    {
                        Monitor.Wait(lockObject);
                    }
                }

                // Loop until we exhaust the queue
                bool queueFull = true;
                while (queueFull && !Stopping)
                {
                    // Get an item from the queue
                    AsyncOperation asyncOp  = null;
                    object         request  = null;
                    int            priority = 0;
                    lock (lockObject)
                    {
                        // Check queues
                        Tuple <AsyncOperation, int> work = GetWork();
                        asyncOp  = work.Item1;
                        priority = work.Item2;
                        if (asyncOp != null)
                        {
                            request = asyncOp.UserSuppliedState;
                        }

                        // Check if the item was removed
                        if (request != null && cancelledItems.ContainsKey(request))
                        {
                            request = null;
                        }
                    }

                    if (request != null)
                    {
                        Exception error = null;
                        // Start the work
                        QueuedWorkerDoWorkEventArgs arg = new QueuedWorkerDoWorkEventArgs(request, priority);
                        try
                        {
                            // Raise the do work event
                            OnDoWork(arg);
                        }
                        catch (Exception e)
                        {
                            error = e;
                        }

                        // Raise the work complete event
                        QueuedWorkerCompletedEventArgs arg2 = new QueuedWorkerCompletedEventArgs(request,
                                                                                                 arg.Result, priority, error, arg.Cancel);
                        if (!Stopping)
                        {
                            asyncOp.PostOperationCompleted(workCompletedCallback, arg2);
                        }
                    }
                    else if (asyncOp != null)
                    {
                        asyncOp.OperationCompleted();
                    }

                    // Check if the cache is exhausted
                    lock (lockObject)
                    {
                        queueFull = !IsWorkQueueEmpty();
                    }
                }
            }
        }