1

我有两个用户控件。第一个包含一个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));
            }
        }
    }
}

现在这是我首先为MainControlwho 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.

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

在后台任务中构建这些用户控件以使 UI 不会冻结可能是什么技巧?

4

2 回答 2

4

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

因此,现在是时候以不同的方式考虑解决方案了。创建几十个控件没问题;UI 会处理得很好。您正在谈论向列表控件添加数百或数千个项目,而这只是一个无法使用的 UI。因此,正确的解决方案是重新考虑您的 UI 设计。也许您可以将结果划分为类别或其他内容。

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

于 2013-11-04T03:23:49.440 回答
-1

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

您可以使用此工作流程:

  • 实现一个 EventHandler,它在初始化完成时引发。
  • 显示一个空的 MainControl 并说“正在加载”
  • 在另一个线程中构建所有 UI
  • 构建所有 UI 时,引发完成事件
  • 此事件的侦听器会将 SubControls 添加到您的 MainControl

[...] 因为它对实际 UI 没有任何影响;它们只是被添加到一个临时列表中

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

于 2013-11-03T00:02:48.903 回答