简体   繁体   中英

Making Thread-Safe Calls by using BackgroundWorker

i want to use BackgroundWorker for my code.

 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        if (worker.CancellationPending == true)
        {
            e.Cancel = true;

        }
        else
        {
            hladat();
        }

    }

and my function hladat() is

            int x = 0;


            while (x < 130)
            {

                for (trackBar7.Value = x; trackBar7.Value < 250-x; trackBar7.Value += 2)
                {
                    minR = trackBar7.Value;
                    System.Threading.Thread.Sleep(15);

                    if (((CV - CV / 4) < RV) && (RV < CV)&&(vyhovujedlzka()))
                    {
                        break;
                    }
                }

                trackBar7.Value = x;
                minR = x;

                for (trackBar8.Value = 250 - x; trackBar8.Value > x; trackBar8.Value -= 2)
                {
                    maxR = trackBar8.Value;
                    System.Threading.Thread.Sleep(15);

                    if (((CV - CV / 4) < RV) && (RV < CV) && (vyhovujedlzka()))
                    {
                        break;
                    }
                }

                trackBar8.Value = 250-x;
                maxR = 250-x;

                for (trackBar9.Value = 0; trackBar9.Value < 254; trackBar9.Value += 2)
                {
                    minG = trackBar9.Value;
                    System.Threading.Thread.Sleep(15);

                    if (((CV - CV / 4) < RV) && (RV < CV) && (vyhovujedlzka()))
                    {
                        break;
                    }

                }

                if (((CV - CV / 4) < RV) && (RV < CV) && (vyhovujedlzka()))
                {
                    break;
                }
                x = x + 10;
                trackBar9.Value = 0;
                minG = 0;


        }

and when i start bgWorker it give me error for this part of code

trackBar7.Value = x

"Cross-thread operation not valid: Control 'trackBar7' accessed from a thread other than the thread it was created on."

how can i repair this code???... thnx and sorry for my english =//

Set WorkerReportsProgress() to True for your BackgroundWorker() control, then wire up the ProgressChanged() event.

Now change:

trackBar7.Value = x;

To:

backgroundWorker1.ReportProgress(x, trackBar7);

In the ProgressChanged() event, cast e.UserState back to TrackBar and set its Value() to e.Percentage :

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        TrackBar tb = (TrackBar)e.UserState;
        tb.Value = e.ProgressPercentage;
    }

Alternate approach:

If you want to do it all from within hladat() itself, change:

        trackBar7.Value = x;

To:

        trackBar7.Invoke((MethodInvoker)delegate{
            trackBar7.Value = x;
        });

http://msdn.microsoft.com/en-us/library/ms171728%28v=vs.85%29.aspx

Use this function to set the value:

delegate void SetValueCallback(TrackBar trackbar, int value);

private void SetValue(TrackBar trackbar, int value)
{
    // InvokeRequired required compares the thread ID of the
    // calling thread to the thread ID of the creating thread.
    // If these threads are different, it returns true.
    if (trackbar.InvokeRequired)
    {   
         SetValueCallback d = new SetValueCallback(SetValue);
         this.Invoke(d, new object[] {trackbar, value });
    }
    else
    {
         trackbar.Value = value;
    }
 }

This should correct the set part.

As for the reading; it's best to write the Value to a variable. In that case you won't need to access a UI-control for you logic, just read the variable.

Something like:

for (int c = x; c < 250-x; c += 2)
{
    SetValue(trackBar7, c); 
    //etc.

You have a few options, either do the Invoke method Stefan mentioned , ReportProgress like Idle_Mind mentioned , or another option is to use IProgress<T> (if you are on .NET 4.0 you can get the classes and interfaces from the Microsoft.Bcl NuGet package).

The way it works is you create a Progress<T> object and set it up to do whatever update you need on the UI thread (it captures the SynchronizationContext of the thread it is currently running on when you create it, so create it on the UI thread), you then pass a IProgress<T> interface to the method you doing the updating and that method calls Report(T)

private Form1()
{
    //Snip

    trackBar7Progress = new Progress<int>(value => trackBar7.Value = value);
    trackBar8Progress = new Progress<int>(value => trackBar8.Value = value);
    trackBar9Progress = new Progress<int>(value => trackBar9.Value = value);
}

IProgress<int> trackBar7Progress;
IProgress<int> trackBar8Progress;
IProgress<int> trackBar9Progress;

then inside hladat() change your trackBar#.Value = x calls to trackBar#Progress.Report(x)

//Snip

trackBar7Progress.Report(x);
minR = x;

for (trackBar8.Value = 250 - x; trackBar8.Value > x; trackBar8.Value -= 2)
{
    maxR = trackBar8.Value;
    System.Threading.Thread.Sleep(15);

    if (((CV - CV / 4) < RV) && (RV < CV) && (vyhovujedlzka()))
    {
        break;
    }
}

trackBar8Progress.Report(250-x);
maxR = 250-x;

for (trackBar9.Value = 0; trackBar9.Value < 254; trackBar9.Value += 2)
{
    minG = trackBar9.Value;
    System.Threading.Thread.Sleep(15);

    if (((CV - CV / 4) < RV) && (RV < CV) && (vyhovujedlzka()))
    {
        break;
    }

}

if (((CV - CV / 4) < RV) && (RV < CV) && (vyhovujedlzka()))
{
    break;
}
x = x + 10;
trackBar9Progress.Report(0);
minG = 0;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM