To be honest, I'm a little bit lame when it comes to threading ;) So开发者_StackOverflow社区 I'm asking for a little help.
Let's assume, we have some kind of control on which we can draw some charts. There's also a method that draws a chart on this control. The problem is that the charting method has access only to one of the fields of the control and we need to refresh the control when the chart is ready.
So let's assume our control looks like that:
class ChartingControl : System.Windows.Forms.Control
{
public Canvas canvas;
public void Refresh();
/*
... other fields/methods
*/
}
where Canvas
is a class used to draw the image (something like Graphics).
canvas
object (we cannot change it), so it looks like that:
public static void DrawChart(canvas)
{ /* draw */ }
This method can be called from a separate thread, background worker etc... And I need to synchronize it with the main thread and call Refresh()
when the chart is ready.
Right now when the chart is ready, I set a flag on canvas object
public static void DrawChart(canvas)
{ /* draw */
canvas.Tag = true; // chart is ready
}
And I have a background worker running inside of the charting control and listening if the canvas.Tag
field has changed and if so, it calls Refresh()
But it seems that my method is a little bit rought, easy-to-fail etc... Is there any better method to improve it?
Limitations:
- we cannot modifyCanvas
class. The only thing we can use is the Tag
field (of type object
- we can modify ChartingControl
class and drawing method.
- There can be many charting controls
- We have no control over how DrawChart
is called. It can be called in a separate thread, or not. It is called elsewhere. All we can do is to create the control and the DrawChart method and try to comunicate them somehow
Solution
OK, I solved it this way: inChartingControl
I created a ManualResetEvent manualReset
and a background worker.
Bacground worker waits for the manualReset
:
void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
manualReset.WaitOne(); // Wait for a chart to be ready
}
and in the end calls Reset() method
void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
Refresh();
}
I pass the manualReset
object inside canvas.Tag
and inside drawing method, when the chart is ready I call manualReset.Set();
to pass the signal that chart is ready.
OK, I solved it this way: in ChartingControl
I created a ManualResetEvent manualReset
and a background worker.
Bacground worker waits for the manualReset
:
void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
manualReset.WaitOne(); // Wait for a chart to be ready
}
and in the end calls Reset() method
void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
Refresh();
}
I pass the manualReset
object inside canvas.Tag
and inside drawing method, when the chart is ready I call manualReset.Set();
to pass the signal that chart is ready.
Supposing you deal with synchronization of access to the Canvas object, I will just recommend that you do
myChartingControl.Invoke(new Action(myChartingControl.Refresh));
from another thread that draws the chart
BackgroundWorker will help you
void StartDrawChart (){
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync()
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Refresh();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
DrawChart(this.canvas);
}
精彩评论