I have a wpf application, It has mainWindow
that creates _otherWindow
that displays on a secondary monitor. Both windows have elements that need to change along with time. (mainWindow
updates an Image
and also plots
a graph, finally _otherWindow
updates a shape
position depending on some computations).
What is my problem? well, I am reading a video frame by frame within a Thread
(however I would like to allow this with stream taken with a camera). And as I update GUI every frame in a certain time, Application is getting a heavy load and is getting slow...
I realized that commenting either mainWindow updating Image
, or commenting _otherWindow
updating shape position
codes make the application run nice, but the issue is when they run together.
Here is a detailed description
First I compute some things inside _otherWindow
and compute position of a shape
.
Then I compute some stuff related to image
and the update frame
adding some stuff to bitmap
Then I update position of shape inside _otherWindow
Finally I plot results (the plot needs data gotten from mainWindow
and _otherWindow
)
For this, I use tasks and wait for them.
I have this:
private Thread _camera;
private void CaptureVideo()
{
_camera = new Thread(CaptureVideoCallback)
{
Priority = ThreadPriority.Highest
};
_camera.Start();
}
private VideoCapture _capture;
private void CaptureVideoCallback()
{
//some computing here read from a video file...
_capture = new VideoCapture("someVideo.mp4");
for (var i = 0; i < _capture.FrameCount; i++)
{
_capture.Read(_frame);
if (_frame.Empty()) return;
//*************task that does heavy computation in other class
var heavyTaskOutput1 = Task.Factory.StartNew(() =>
{
_otherWindow.Dispatcher.Invoke(() =>
{
ResultFromHeavyComputationMethod1 = _otherWindow.HeavyComputationMethod1();
});
}
);
////*************task that does heavy computation in current class
var heavyTaskOutput2 = Task.Factory.StartNew(() =>
{
ResultFromHeavyComputationMethod2 = HeavyComputationMethod2(ref _frame);
var bitmap = getBitmapFromHeavyComputationMethod2();
bitmap.Freeze();
//update GUI in main thread
Dispatcher.CurrentDispatcher.Invoke(() => ImageSource = bitmap);
});
////*************wait both task to complete
Task.WaitAll(heavyTaskOutput1, heavyTaskOutput2 );
//update _otherWindow GUI
var outputGui = Task.Factory.StartNew(() =>
{
_otherWindow.Dispatcher.Invoke(() =>
{
_otherWindow.UpdateGui();
});
}
);
outputGui.Wait();
////*************plot in a char using gotten results, UPDATE GUI
Task.Run(() =>
{
PlotHorizontal();
});
}
}
What would be a good way to speed this up? I mean I know that GUI stuff need to be done on main thread, but this is slowing down things.
Edit
Have changed code as Clemens suggested:
//*************task that does heavy computation in other class
var heavyTaskOutput1 = Task.Run(() =>
{
ResultFromHeavyComputationMethod1 = _otherWindow.HeavyComputationMethod1();
}
);
////*************task that does heavy computation in current class
var heavyTaskOutput2 = Task.Run(() =>
{
ResultFromHeavyComputationMethod2 = HeavyComputationMethod2(ref _frame);
var bitmap = getBitmapFromHeavyComputationMethod2();
bitmap.Freeze();
//update GUI in main thread
Dispatcher.CurrentDispatcher.Invoke(() => ImageSource = bitmap);
});
////*************wait both task to complete
Task.WaitAll(heavyTaskOutput1, heavyTaskOutput2);
//update _otherWindow GUI
var outputGui = Task.Run(() =>
{
_otherWindow.Dispatcher.Invoke(() =>
{
_otherWindow.UpdateGui();
});
}
);
outputGui.Wait();