在新线程中单击“C#更新图像”按钮

本文关键字:更新 图像 按钮 单击 新线程 线程 | 更新日期: 2023-09-27 18:27:53

我的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()可以解决我的问题,这就是为什么我把它放在那里。。。。

在新线程中单击“C#更新图像”按钮

您可以推断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秒。

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