WPF UI冻结 - UI线程冲突?

时间:2015-05-28 23:32:05

标签: c# wpf multithreading

我尝试使用WPF创建图片幻灯片效果 使用新图像更新幻灯片的方法在Windows.Forms.Timer中每隔几秒调用一次,并在Task内的自己的线程中运行(如下所示)。

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();
           }));
        });
    }

同时,在画布的底部有一个滚动的文本横幅。这也是在它自己的线程中运行,通过Dispatcher更新UI。

每个图像,滚动文本幻灯片都将暂停一两秒,似乎在等待图像加载。这种行为是出乎意料的,因为每个元素都在一个单独的线程中。


这可能是更新UI线程的两个Task线程之间的冲突吗? 可能导致这种情况的原因是什么?

1 个答案:

答案 0 :(得分:6)

将代码放在另一个线程上的代码不会将工作放在另一个线程上。您的BeginInvoke正在将其发送回UI线程,您的所有工作都在那里完成。

在执行BeginInvoke调用之前执行繁重的工作,以便工作实际发生在后台线程上。

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();
       }));
    });

我怀疑你的横幅广告实际上并没有在另一个帖子上工作,你可能想要查看它。

如果可能的话,更好的解决方法是将BitmapFromUri重写为异步并且根本不使用线程。

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;
}