2013-08-16 31 views
3

我在我的XAML中有一个Image标签的列表,我希望一个接一个地更新并在其中间休息。C#在按钮上更新图片点击新主题

我有以下代码,但它们都只是立即更新,并且UI保持冻结状态直到完成。

请您帮助我更新'生活'作为图像源设置?

这是我到目前为止有:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

namespace JobMonitor 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     // Add the test lights to a list 
     private readonly Dictionary<int, Image> imageDictionary; 

     public MainWindow() 
     { 
      InitializeComponent(); 

      imageDictionary = new Dictionary<int, Image> 
      { 
       {1, TestLight1}, 
       {2, TestLight2}, 
       {3, TestLight3}, 
       {4, TestLight4}, 
       {5, TestLight5}, 
       {6, TestLight6}, 
      }; 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      Dispatcher.InvokeAsync(ChangeImage); 

     } 

     private void ChangeImage() 
     { 
      // Loop through each of the tests 
      foreach (var testLight in imageDictionary) 
      { 
       ChangeImageLights(testLight.Value); 

       Thread.Sleep(1000); 
      } 
     } 

     private void ChangeImageLights(Image img) 
     { 

      var myImage3 = new Image(); 
      var redLightImage = new BitmapImage(); 
      redLightImage.BeginInit(); 
      redLightImage.UriSource = new Uri("red_light.png", UriKind.Relative); 
      redLightImage.EndInit(); 
      myImage3.Stretch = Stretch.Fill; 
      myImage3.Source = redLightImage; 

      img.Source = redLightImage; 
     } 
    } 
} 

XAML:

<Image Margin="0,0,20,0" Height="40" Source="green_light.png" Stretch="Fill" Name="TestLight1" /> 
<Image Margin="0,0,20,0" Height="40" Source="green_light.png" Stretch="Fill" Name="TestLight2" /> 
<Image Margin="0,0,20,0" Height="40" Source="green_light.png" Stretch="Fill" Name="TestLight3" /> 
<Image Margin="0,0,20,0" Height="40" Source="green_light.png" Stretch="Fill" Name="TestLight4" /> 
<Image Margin="0,0,20,0" Height="40" Source="green_light.png" Stretch="Fill" Name="TestLight5" /> 
<Image Margin="0,0,20,0" Height="40" Source="green_light.png" Stretch="Fill" Name="TestLight6" /> 

我认为使用Dispatcher.InvokeAsync()将是回答我的烦恼这就是为什么我已经把它放在那里。 ...

回答

3

您可以推断出InvokeAsync实际上并未在另一个线程上运行,因为您可以执行中的操作0。一种方法是利用一个BackgroundWorker

// new private class variable 
private BackgroundWorker _worker = new BackgroundWorker(); 

// constructor code 
public .ctor() 
{ 
    _worker.WorkerReportsProgress = true; 
    _worker.DoWork += (s, e) => 
    { 
     // Loop through each of the tests 
     foreach (var testLight in imageDictionary) 
     { 
      _worker.ReportProgress(1, testLight.Value); 

      Thread.Sleep(1000); 
     } 
    } 
    _worker.ProgressChanged += (s, e) => 
    { 
     var myImage3 = new Image(); 
     var redLightImage = new BitmapImage(); 
     redLightImage.BeginInit(); 
     redLightImage.UriSource = new Uri("red_light.png", UriKind.Relative); 
     redLightImage.EndInit(); 
     myImage3.Stretch = Stretch.Fill; 
     myImage3.Source = redLightImage; 

     ((Image)e.UserState).Source = redLightImage; 
    } 
} 

BackgroundWorker启动一个新的线程,运行在该线程DoWork处理程序。然后,当您拨打ReportProgress时,它会处理切换线程,以便您可以实际修改ProgressChanged处理程序中的UI。

现在后台线程会在报告更多进度之前实际休眠1秒。

2

如何使用async/await

async private void ChangeImage() 
{ 
    // Loop through each of the tests 
    foreach (var testLight in imageDictionary) 
    { 
     ChangeImageLights(testLight.Value); 

     await Task.Delay(1000); 
    } 
} 

这样你就不需要的BackgroundWorker。只需调用ChangeImage

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    ChangeImage(); 
} 
+1

太棒了,这工作太棒了! – Luke