3

我的 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()将是我的麻烦的答案,这就是为什么我把它放在那里....

4

2 回答 2

3

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

于 2013-08-16T12:06:40.977 回答
2

How about using async/await ?

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

        await Task.Delay(1000);
    }
}

That way you wouldn't need BackgroundWorker. Just invoke ChangeImage

private void Button_Click(object sender, RoutedEventArgs e)
{
    ChangeImage();
}
于 2013-08-16T12:24:53.123 回答