我使用浏览文件对话框允许用户选择多个图像。如果选择了大量图像,则需要一点点。以下是我对所选图像的处理示例。我遍历文件路径到图像并创建用户控件的实例,用户控件有一个Image控件和一些其他控件。我创建此控件的实例,然后将其添加到关联窗口xaml文件中创建的现有stackPanel。下面的示例工作正常,但我正在尝试更好地理解BackGroundWorker,我得到了如何设置它的基础知识,它的事件,并传回一个可以更新进度条的值,但因为我的循环需要下面的up time将usercontrol实例添加到现有的stackPanel,它将无法工作,位于不同的线程中。 BackGroundWorker是否可以用于这样的示例?如果是这样,更新线程外部的ui(我的堆栈面板)的最佳方法是什么。我对wpf相当新,并且从未使用BackGroundWorker,除了测试它只是用int值更新进度,所以我希望这个问题有意义,如果我离开目标只是让我知道。谢谢你的任何想法。
我现在如何做的示例,它可以正常工作。
protected void myMethod(string[] fileNames) {
MyUserControl uc;
foreach (String imagePath in fileNames) {
uc = new MyUserControl();
uc.setImage(imagePath);
stackPanel.Children.Add(uc);
progressBar.Value = ++counter;
progressBar.Refresh();
}
}
在这个类下面我有这个所以我可以进行progressBar刷新:
public static class extensionRefresh {
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement) {
uiElement.Dispatcher.Invoke(DispatcherPriority.Background, EmptyDelegate);
}
}
答案 0 :(得分:2)
查看这篇文章 Building more responsive apps with the Dispatcher
现在您已经了解了Dispatcher的工作原理,您可能会惊讶地发现在大多数情况下您将无法使用它。在Windows Forms 2.0中,Microsoft引入了一个非UI线程处理类,以简化用户界面开发人员的开发模型。该类称为BackgroundWorker
在WPF中,此模型使用DispatcherSynchronizationContext类进行扩展。通过使用BackgroundWorker,Dispatcher将自动用于调用跨线程方法调用。好消息是,由于您可能已经熟悉这种常见模式,因此可以在新的WPF项目中继续使用BackgroundWorker
基本上方法是
BackgroundWorker _backgroundWorker = new BackgroundWorker();
// Set up the Background Worker Events
_backgroundWorker.DoWork += _backgroundWorker_DoWork;
_backgroundWorker.RunWorkerCompleted += _backgroundWorker_RunWorkerCompleted;
// Run the Background Worker
_backgroundWorker.RunWorkerAsync(5000);
// Worker Method
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Do something
}
// Completed Method
void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Doing UI stuff
if (e.Cancelled)
{
statusText.Text = "Cancelled";
}
else if (e.Error != null)
{
statusText.Text = "Exception Thrown";
}
else
{
statusText.Text = "Completed";
}
}
答案 1 :(得分:1)
单独使用BackgroundWorker无法解决您的问题,因为在DoWork
部分期间创建的元素仍然来自非UI线程。您必须在要在另一个线程上使用的任何对象上调用Freeze
。但是,只有某些UI对象可以冻结。您可能必须在后台线程上将图像作为BitmapImage
加载,然后在UI线程上创建其余的用户控件。这仍然可以实现您的目标,因为在图像中加载可能是最重量级的操作。
请记住将BitmapImage.CacheOption
设置为OnLoad
,因此它实际上会在您创建对象时加载图像,而不是等到需要显示它。