2013-08-16 54 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