【问题标题】:Create UserControl in other thread在其他线程中创建 UserControl
【发布时间】:2017-04-23 13:48:18
【问题描述】:

我正在尝试在另一个线程中创建一个 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
}

【问题讨论】:

  • 看到这个:stackoverflow.com/questions/12387687/… ...当你使用任务时...如果它被安排在后台运行...它使用一个线程池线程...这将有已使用 MTA 初始化(已经是多线程单元)。一旦初始化到一个特定的单元,它就不能被改变......即使你可以改变它的单元,你也不想改变它,因为线程池中的线程会被重用。
  • 创建控件需要这么长时间?控件通常不会花费很长时间来加载...控件是否可能加载某种您可以单独加载的数据?

标签: c# wpf


【解决方案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;
    }

}

【讨论】:

    猜你喜欢
    • 2020-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 1970-01-01
    相关资源
    最近更新 更多