我有一个非常复杂的UserControl需要在运行时创建。这个创建将GUI冻结大约5秒钟(这是不可接受的)。
我尝试将此操作移动到后台工作器中,最终得到此异常:
调用线程必须是STA,因为许多UI组件都需要这个。
我知道我无法使用MTA线程来创建UserControl / UI元素。我尝试使用BackgroundWorker和Dispatcher的组合,但它不起作用。
<小时/> 首先尝试
private void LetsGo()
{
var backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += backgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
DispatcherOperation dispatcherOperation = Dispatcher.CurrentDispatcher.BeginInvoke(new Action(this.GenerateControlAsync), DispatcherPriority.Background);
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
// Cancelled
}
else if (e.Error != null)
{
//Exception Thrown
}
else
{
//Completed
}
}
private void GenerateControlAsync () {
this.Control = new TimeConsumingUserControl();
}
上面的代码不起作用,方法this.GenerateControlAsync不会被执行。
<小时/> 第二次尝试
private async void GenerateControl()
{
this.Control = await Dispatcher.CurrentDispatcher.InvokeAsync<UserControl>(this.GenerateControlAsync);
}
private UserControl GenerateControlAsync()
{
return new TimeConsumingUserControl();
}
此示例正在运行,但它会一直冻结GUI线程。
<小时/> 我正在使用WPF和.net Framework 4.5。
请注意,方法GenerateControlAsync()不是简单地创建UserControl的实例,涉及更多逻辑。
回答@ HighCore 的问题: 实际上,UserControl的XAML代码通过XSLT从xml文件转换而来,Codebehind是使用CodeDOM生成的。整个事情需要编译并包装到一个程序集中。我使用assembly.CreateInstance()来获取UserControl的一个实例。该行抛出引用的异常。在我的GUI中,我有一个ContentControl,它与我的ViewModel中的UserControl绑定。生成的数据(如需要转换的xml文件)将从Web服务中检索。
这就是为什么这种方法的执行需要的时间比人们预期的要长一些。
答案 0 :(得分:1)
根据您对创建控件所涉及的所有步骤的描述,看起来您正在将大量工作集中在一起,而这些工作不需要在同一个线程上完成,并尝试在UI或背景线程。您应该在UI线程(实际的UserControl
实例化)上执行必要的最少工作量,并在工作线程上执行其他所有操作。你应该做两个步骤而不是单个异步工作单元,而使用async-await非常简单。看起来应该更像这样:
var dynamicAssembly = await this.GenerateControlAssemblyAsync();
this.Control = this.GenerateControlFromAssembly(dynamicAssembly);
由于await的工作方式,第二行将自动在原始(UI)线程上运行,因此不需要任何Dispatcher
次调用。在GenerateControlAssemblyAsync
中,您应该使用Task.Run
并执行其中的所有其他代码。 GenerateControlFromAssembly
除了实例化UC实例之外什么都不做。
答案 1 :(得分:1)
你需要对你的装配生成进行分块。您的程序集生成需要花费太多时间,您需要将所有内容放在另一个线程中,并且只在同一个线程中生成DIRECT Ui组件。
有一种很酷的方法可以从流中加载Xaml并以块的形式进行,而不会堵塞UI。看看:http://msdn.microsoft.com/en-us/library/aa346591.aspx