1

I'm an indolent developer like other :) and why I try to write a static method to use BackgroundWorker any where. this method is the blew:

public static void RunInThread( DoWorkEventHandler method
                                    ,ProgressChangedEventHandler progressHandler
                                    ,RunWorkerCompletedEventHandler completed)
    {
        var bkw = new BackgroundWorker();
        bkw.DoWork += method;
        bkw.ProgressChanged += progressHandler;
        bkw.RunWorkerCompleted += completed;
        bkw.WorkerReportsProgress = true;
        bkw.RunWorkerAsync();
    }

but i have a problem for use the BackgroundWorker.ReportProgress method. Is there anyone here who can help me? tnx

2 Answers2

0

What if instead of returning void from RunInThread you return an object of BackgroundWorker class(bkw) and then in your DoWork use that instace to call backgroundWorker.ReportProgress();

Haris Hasan
  • 29,856
  • 10
  • 92
  • 122
0

While Haris's solution is an acceptable "quick fix," you have a major design flaw with your static method; the BackgroundWorker class, being a Component, implements IDisposable, and therefore should be disposed at the end of its life.

The best way to recreate your pattern would be to manually invoke your work function on another thread. The only downside to this is that you must call Dispatcher.Invoke to interact with anything on the UI thread while you are updating progress. Here's a sample of how you could do it.

using System.Threading;

public static void RunInThread<TProgress>(
    Action<Action<TProgress>> worker,
    Action<TProgress> updateProgress,
    Action workerCompleted)
{
    Thread workerThread = new Thread(() =>
    {
        worker(updateProgress);
        workerCompleted();
    });

    workerThread.Start();
}

Because it's a generic method, you can use it to report any type of progress you like back. Here's an example of how you could call it:

RunInThread<double>(
    updateProgress =>
    {
        Thread.Sleep(500);
        updateProgress(0.5);

        Thread.Sleep(500);
        updateProgress(1);
    },
    progress =>
    {
        this.Dispatcher.Invoke(() =>
        {
            progressLabel.Text = progress.ToString();
        });
    },
    () =>
    {
        this.Dispatcher.Invoke(() =>
        {
            progressLabel.Text = "Finished!";
        });
    }
);

You can also customize this method very easily to create overload that add ease when working with a single parameter or a return value.

public static void RunInThread<TProgress, TParameter>(
    Action<Action<TProgress>, TParameter> worker,
    Action<TProgress> updateProgress,
    Action workerCompleted,
    TParameter parameter)
{
    Thread workerThread = new Thread(() =>
    {
        worker(updateProgress, parameter);
        workerCompleted();
    });

    workerThread.Start();
}

public static void RunInThread<TProgress, TResult>(
    Func<Action<TProgress>, TResult> worker,
    Action<TProgress> updateProgress,
    Action<TResult> workerCompleted)
{
    Thread workerThread = new Thread(() =>
    {
        TResult result = worker(updateProgress);
        workerCompleted(result);
    });

    workerThread.Start();
}

public static void RunInThread<TProgress, TParameter, TResult>(
    Func<Action<TProgress>, TParameter, TResult> worker,
    Action<TProgress> updateProgress,
    Action<TResult> workerCompleted,
    TParameter parameter)
{
    Thread workerThread = new Thread(() =>
    {
        TResult result = worker(updateProgress, parameter);
        workerCompleted(result);
    });

    workerThread.Start();
}

I would also recommend you add some error-handling code in case anything blows up within your work function, but I'll leave that exercise to you.

Adam Maras
  • 26,269
  • 6
  • 65
  • 91