开发者

Update C# Chart using BackgroundWorker

I am currently trying to update a chart which is on my form to the background worker using:

bwCharter.RunWorkerAsync(chart1);

Which runs:

private void bcCharter_DoWork(object sender, DoWorkEventArgs e)
{
     System.Windows.Forms.DataVisualization.Charting.Chart chart = null;

     // Convert e.Argument to chart
     //..
     // Converted..

     chart.Series.Clear();
     e.Result=chart;

     setChart(c.chart);
}
private void setChart(System.Windows.Forms.DataVisualization.Charting.Chart arg)
{
     if (chart1.InvokeRequired)
     {
         chart1.Invoke(new MethodInvoker(delegate { setChart(arg); }));
         return;
     }

     chart1 = arg;
}

However, at the point of clearing the series, an exception is thrown.

Basically, I want to do a whole lot more processing after clearing the series, which slows the GUI down completely - so wanted this in another thread.

I thought that by passing it as an argument, I s开发者_开发技巧hould be safe, but apparently not!

Interestingly, the chart is on a tab page. I can run this over and over if the tabpage is in the background, but if I run this, look at the chart, hide it again, and re-run, it throws the exception. Obviously, it throws if the chart is in the foreground as well.

Can anyone suggest what I can do differently?

Thanks!


EDIT: I know that this can be done in the form thread, as when I assign it back again. However the whole point of using a background worker is to avoid grinding the whole program to a halt. As I said, there is a lot more processing than just this one command.

I assumed that passing it as an argument would allow me to access it in that thread unhindered, but is there a chance that this passed chart still points back to the original chart in some way? If so, how can this be overcome?

I want to block the GUI thread as little as possible - so there seems no point in just invoking every command.


If you want to clear it first, then do a lot of asynchronous work before you redisplay it, why don't you call chart.Series.Clear(); before you invoke the BackgroundWorker? In that case it gets cleared on the main UI thread, then you perform som async work before you again set the chart from the UI thread.

Also, when using a BackgroundWorker, I would use the inbuilt ReportProgress and WorkerCompleted events to avoid the manual cross-thread invoking. That's part of the reason of using the BackgroundWorker in the first place to get this kind of functionality for "free". So setting the chart should be done in the WorkerCompleted to simplify your code (even if that is not the source of the problem in this case).


Check for Invoke Required in bcCharter_DoWork, if yes put the Clear method call in a delegate too.

 if (InvokeRequired)
 {          

     Invoke(new MethodInvoker(delegate 
     { 
       chart.Series.Clear();
       e.Result=chart;               
     }));

     return;
 }


I agree with the analysis in the previous posts : you ask a thread to access to a resource of another thread.
Like you used a BackgroundWorker I suggest you to use the Dispatcher :

private void bcCharter_DoWork(object sender, DoWorkEventArgs e)
{
    Chart chart = null;

    Dispatcher.Invoke(DispatcherPriority.Normal,
        new Action(() =>
            {
                chart.Series.Clear();
            }));
}


The problem you are encountering is that you cannot access UI elements on threads other than the one they were created on. However, in your case you can simply clear the chart before calling the background worker.

You can manually marshal UI element access to the correct thread from another thread using Control.Invoke.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜