C#更新按钮上的图像单击新线程

时间:2013-08-16 11:56:28

标签: c# .net wpf

我的XAML中有一个Image标签列表,我希望一个接一个地更新,然后睡在中间。

我有以下代码,但它们都只是立即更新,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()会解决我的烦恼,这就是为什么我把它放在那里......

2 个答案:

答案 0 :(得分:3)

您可以推断InvokeAsync实际上并未在另一个线程上运行,因为您可以在ChangeImageLights中执行操作。一种方法是利用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秒钟。

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