Reputation: 365
I'm trying to create an image slideshow effect with WPF
.
The method to update the slideshow with a new image is called every few seconds in a Windows.Forms.Timer
, and runs in it's own thread within a Task
(as seen below).
private void LoadImage()
{
Task t = Task.Run(() =>
{
this.Dispatcher.BeginInvoke((Action)(() =>
{
TimeSpan delay = new TimeSpan(0, 0, 0, 0, 0);
Fader.ChangeSource(image, BitmapFromUri(new Uri(compPath + oComps[nCount].name)), delay, delay);
image.Visibility = System.Windows.Visibility.Visible;
mediaElement.Stop();
mediaElement.Close(); ;
mediaElement2.Stop();
mediaElement2.Close();
mediaElement.Visibility = System.Windows.Visibility.Collapsed;
mediaElement2.Visibility = System.Windows.Visibility.Collapsed;
imageLoop.Interval = oComps[nCount].duration;
nCount++;
imageLoop.Start();
}));
});
}
Simultaneously, there is a scrolling text banner across the bottom of the canvas in an overlay. This too is running in it's own thread, updating the UI through a Dispatcher
.
Every few images, both the scrolling text and the slideshow will pause for a second or two, seemingly waiting for the image to load. This behaviour is unexpected as each element is in a seperate thread.
Could this be a conflict between the two Task threads updating the UI thread?
What could be causing this?
Upvotes: 1
Views: 3041
Reputation: 127603
Your code to put work on another thread does not put the work on another thread. Your BeginInvoke
is sending it back to the UI thread and all your work is being done there.
Do the heavy work before you do the BeginInvoke call so the work actually happens on the background thread.
private void LoadImage()
{
Task t = Task.Run(() =>
{
//I assume BitmapFromUri is the slow step.
var bitmap = BitmapFromUri(new Uri(compPath + oComps[nCount].name);
//Now that we have our bitmap, now go to the main thread.
this.Dispatcher.BeginInvoke((Action)(() =>
{
TimeSpan delay = new TimeSpan(0, 0, 0, 0, 0);
//I assume Fader is a control and must be on the UI thread, if not then move that out of the BeginInvoke too.
Fader.ChangeSource(image, bitmap), delay, delay);
image.Visibility = System.Windows.Visibility.Visible;
mediaElement.Stop();
mediaElement.Close(); ;
mediaElement2.Stop();
mediaElement2.Close();
mediaElement.Visibility = System.Windows.Visibility.Collapsed;
mediaElement2.Visibility = System.Windows.Visibility.Collapsed;
imageLoop.Interval = oComps[nCount].duration;
nCount++;
imageLoop.Start();
}));
});
I suspect your banner is also not actually doing work on the other thread, you may want to look in to it.
A even better solultion if possible is rewrite BitmapFromUri to be async and not use threads at all.
private async Task LoadImageAsync()
{
TimeSpan delay = new TimeSpan(0, 0, 0, 0, 0);
var bitmap = await BitmapFromUriAsync(new Uri(compPath + oComps[nCount].name);
Fader.ChangeSource(image, bitmap), delay, delay);
image.Visibility = System.Windows.Visibility.Visible;
mediaElement.Stop();
mediaElement.Close(); ;
mediaElement2.Stop();
mediaElement2.Close();
mediaElement.Visibility = System.Windows.Visibility.Collapsed;
}
Upvotes: 7