如何初始化另一个线程中的重控件?

时间:2013-11-02 22:10:15

标签: c# multithreading xaml windows-runtime

我提升了两个用户控件。 第一个包含一个ItemsControl,我必须用我的第二个用户控件动态填充它。第二个用户控件可以递归地包含另一个ÌtemsControl,因此它是一个非常重要的控件来初始化。

以下是我为SubControl所做的事情:

public sealed partial class SubControl : UserControl
{
    public SubControl(ModelA item)
    {
        this.InitializeComponent();
        this.DataContext = item;

        //if the current item has child items, add them to the ItemsControl:
        if(item.SubItems != null)
        {
            BuildUI(item.SubItems);
        }
    }

    private void BuildUI(List<AbstractModel> data)
    {
        foreach(var item in data)
        {
            var dataItem = item as ModelA;
            //we only want item of type ModelA in our ItemsControl:
            if(dataItem != null)
            {
                SubElements.Items.Add(new SubControl(dataItem));
            }
        }
    }
}

现在,我首先为MainControl ItemsControl(名为Elements)将包含一组SubControl的内容撰写的内容:

public sealed partial class MainControl : UserControl
{
    public MainControl(List<AbstractModel> data)
    {
        this.InitializeComponent();
        BuildUI(data);
    }

    private void BuildUI(List<AbstractModel> data)
    {
        foreach(var item in data)
        {
            var dataItem = item as ModelA;
            if(dataItem != null)
            {
                Elements.Items.Add(item);
            }
        }
    }
}

我注意到在构建这个“树”时UI的小冻结,但我目前正在使用功能非常强大的计算机。我希望应用程序即使在较小的设备(如Windows Surface RT)上也能顺利运行。所以我更改了MainControl代码:

public sealed partial class MainControl : UserControl
{
    public MainControl(List<AbstractModel> data)
    {
        this.InitializeComponent();
        BuildUI(data);
    }

    private async void BuildUI(List<AbstractModel> data)
    {
        var list = new List<SubControl>();
        await Task.Run(() =>
        {
            foreach(var item in data)
            {
                var dataItem = item as ModelA;
                if(dataItem != null)
                {
                    list.Add(new SubControl(dataItem));
                }
            }
        });
        foreach(var item in list)
        {
            Elements.Items.Add(item);
        }
    }
}

我们的想法是在不同的线程中构建所有SubControl,以便不阻止UI,并且当所有用户控件都已初始化时,我们会将它们添加到ItemsControlMainControl。 1}}。

然而,由于数据的编组,这不起作用,即使UI上实际上没有单个SubControl!它在构建SubControl时崩溃,这真的很奇怪,因为它对实际UI没有任何影响;它们只是添加到临时List

在后台任务中构建这些用户控件可能有什么技巧,因此UI不会冻结?

2 个答案:

答案 0 :(得分:4)

Windows UI非常单线程。必须创建每个UI控件,并且仅在单个线程中使用。没有办法解决这个问题。

所以,现在是时候考虑解决方案了。创建几十个控件没有问题;用户界面处理就好了。您正在谈论将数百或数千个项目添加到列表控件,这只是一个无法使用的UI。因此,正确的解决方案是重新考虑您的UI设计。也许你可以把结果分成几类或类别。

如果您已经考虑过您的UI设计并且仍然确定要向用户显示数百或数千个项目,那么答案就是使用virtualization。这比简单的foreach循环更难编码,但它是有效显示大量数据的唯一方法。

答案 1 :(得分:-1)

有很多方法可以做到这一点。

您可以使用此工作流程:

  • 实现一个在初始化完成时引发的EventHandler。
  • 显示空的MainControl并说“loading”
  • 在另一个线程中构建所有UI
  • 构建所有用户界面时,请提高结束事件
  • 此事件的监听器会将SubControls添加到您的MainControl
  

[...]因为它对实际用户界面没有任何影响;它们只是添加到临时列表

顺便说一句:您的代码确实崩溃了,因为您在异步方法中添加了控件,这实际上是一个非GUI线程。所以你的命题错了。