我的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()
会解决我的烦恼,这就是为什么我把它放在那里......
答案 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();
}