我正在尝试在另一个线程中创建一个UserControl。我尝试了1001种方法,但我不能这样做。我有几个错误,最常见的是:"调用线程必须是STA,因为许多UI组件都需要它。"
STA错误,我已经解决了其他类型的事情,例如从另一个线程创建和显示一个表单,但这不一样,我需要一个方法来返回创建的UserControl。我有类似的东西
private async void SetView<T>() where T : UserControl, new()
{
// SHOW LOADING
CurrentView = await Task.Run(() => new T());
// HIDE LOADING
}
答案 0 :(得分:-1)
将值从一个线程传递到另一个线程的最简单方法是使用文件。您将值序列化为文件,然后反序列化它。因此,您必须使用System.Windows.Markup.XamlWriter/XamlReader
类将UserControl
保存到文件并将其加载回来。
下面的示例演示了这一点。您可以使用System.IO.Path.GetTempFileName()
方法保存到临时文件。
<Grid>
<Button Content="Create on new thread" HorizontalAlignment="Left" Margin="25,25,0,0" VerticalAlignment="Top" Width="126" Click="Button_Click_1"/>
<Button Content="Deserialize" HorizontalAlignment="Left" Margin="25,63,0,0" VerticalAlignment="Top" Width="126" Click="Button_Click_2"/>
<Label x:Name="Lbl" Margin="25,127,0,0" VerticalAlignment="Top" Height="105" Width="220"/>
</Grid>
代码:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() => { StartSTATask(create); });
}
bool create()
{
Button btn = new Button();
btn.Content = "Press me";
using (var stream = System.IO.File.Create(@"g:\\button.xaml"))
System.Windows.Markup.XamlWriter.Save(btn, stream);
return true;
}
public static Task<bool> StartSTATask(Func<bool> func)
{
var tcs = new TaskCompletionSource<bool>();
var thread = new Thread(() =>
{
try
{
var result = func();
tcs.SetResult(result);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
using (var stream = System.IO.File.OpenRead(@"g:\\button.xaml"))
{
Button btn = System.Windows.Markup.XamlReader.Load(stream) as Button;
Lbl.Content = btn;
}
}