C# 如何在另一个线程中初始化重载控件?
我举起两个用户控件。 第一个包含一个C# 如何在另一个线程中初始化重载控件?,c#,multithreading,xaml,windows-runtime,C#,Multithreading,Xaml,Windows Runtime,我举起两个用户控件。 第一个包含一个ItemsControl,我必须用第二个用户控件动态填充它。第二个用户控件可能递归地包含另一个ÌtemsControl本身,因此初始化它是一个相当繁重的控件 下面是我为子控制所做的: public sealed partial class SubControl : UserControl { public SubControl(ModelA item) { this.InitializeComponent();
ItemsControl
,我必须用第二个用户控件动态填充它。第二个用户控件可能递归地包含另一个ÌtemsControl
本身,因此初始化它是一个相当繁重的控件
下面是我为子控制所做的:
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));
}
}
}
}
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
code:
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);
}
}
}
公共密封部分类MainControl:UserControl
{
公共主控(列表数据)
{
this.InitializeComponent();
BuildUI(数据);
}
专用异步void BuildUI(列表数据)
{
var list=新列表();
等待任务。运行(()=>
{
foreach(数据中的var项)
{
var dataItem=作为ModelA的项目;
if(dataItem!=null)
{
清单.增加(新分包合同(数据项));
}
}
});
foreach(列表中的变量项)
{
元素。项。添加(项);
}
}
}
我们的想法是在不同的线程中构建所有的子控件
,这样UI就不会被阻塞,当所有的用户控件都初始化后,我们会将它们添加到MainControl
中的ItemsControl
但是,由于数据的编组,这不起作用,即使UI上实际上没有一个子控制
!它在构建子控件时崩溃,这真的很奇怪,因为它对实际的UI没有任何影响;它们只是添加到一个临时的列表中
在后台任务中构建这些用户控件以使UI不冻结有什么诀窍?有很多方法可以做到这一点
您可以使用以下工作流:
- 实现在初始化完成时引发的EventHandler
- 显示一个空的主控件,并说“正在加载”
- 在另一个线程中构建所有UI
- 生成所有UI时,引发finish事件
- 此事件的侦听器将向MainControl添加子控件
[…]因为它对实际用户界面没有任何影响;它们只是添加到临时列表中
顺便说一句:您的代码确实会崩溃,因为您是在一个异步方法中添加控件的,该方法实际上是一个非GUI线程。所以你的观点是错误的。Windows UI是非常单线程的。每个UI控件都必须创建,并且只能从单个线程使用。这是没有办法的
所以,是时候换一种方式来考虑解决方案了。创建几十个控件是没有问题的;UI可以很好地处理这个问题。您正在谈论向列表控件添加数百或数千项,而这只是一个不可用的UI。因此,正确的解决方案是重新思考您的UI设计。也许你可以把结果分成几类
如果您已经考虑过UI设计,并且仍然确定要向用户显示数百或数千项,那么答案就是使用。这比简单的foreach
循环更难编码,但这是有效显示大量数据的唯一方法。您建议在“另一个线程”上构建UI,同时注意不能在非UI线程上添加控件,这与您自己相矛盾。