在新线程中单击“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()
可以解决我的问题,这就是为什么我把它放在那里。。。。
您可以推断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();
}