如果您正在使用 WPF,您确实需要抛开您可能从古老技术中学到的任何和所有概念,并理解并接受 The WPF Mentality。
基本上,您几乎从不需要在 WPF 的过程代码中创建或操作 UI 元素。相反,WPF 适合大量使用DataBinding。
The WPF Threading Model不允许允许您在后台线程中创建或操作 UI 元素的实例,并将它们添加到由“主”UI 线程创建的 Visual Tree。
无论如何,这种事情的需求几乎为零,因为在大多数情况下,创建 UI 元素是一项可以(并且必须)由 UI 线程执行的微不足道的任务。
与其担心可视化树,您应该专注于在后台线程中加载您的数据,然后将其作为DataContext 传递给 UI,以便它可以相应地显示您的数据。
这是一个小例子,它使用ItemsControl 显示用户列表,这些用户在后台线程中异步加载,然后分派到 UI 线程进行显示:
<Window x:Class="WpfApplication7.AsyncItemsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="LightGray" BorderBrush="Black" BorderThickness="1" Margin="2">
<StackPanel>
<TextBlock Text="{Binding LastName}" Margin="2"/>
<TextBlock Text="{Binding FirstName}" Margin="2"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
代码背后:
public partial class AsyncItemsControl : Window
{
public AsyncItemsControl()
{
InitializeComponent();
var dispatcher = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => GetUsers())
.ContinueWith(x => DataContext = x.Result,dispatcher);
}
public List<User> GetUsers()
{
// pretend this method calls a Web Service or Database to retrieve the data, and it takes 5 seconds to get a response:
Thread.Sleep(5000);
return new List<User>
{
new User() {FirstName = "Marty", LastName = "McFly"},
new User() {FirstName = "Emmett", LastName = "Brown"},
new User() {FirstName = "Bufford", LastName = "Tannen"}
};
}
}
数据项:
public class User
{
public string LastName { get; set; }
public string FirstName { get; set; }
}
结果:
请注意,该示例使用 DataBinding,它不会在过程代码中创建或操作 UI 元素,而是使用具有简单 string 属性的简单 User 类进行操作。
还要注意,在 5 秒的“加载”时间内,UI 是响应式的,因为实际工作是由后台线程执行的。
这种方法可以在 UI 和数据之间实现更大的分离,从而在无需更改底层业务/应用程序逻辑的情况下实现更大的 UI 可扩展性和可定制性。
注意ItemsControl 如何创建和呈现显示 3 个数据项所需的适当 UI 元素。 “每个项目的外观”的实际定义是DataTemplate。
我强烈建议阅读本答案中链接的材料,以更深入地了解 WPF 的一般工作原理。
旁注:如果您的目标是 C# 5.0,您可以利用 async / await 并通过删除所有基于 Task 的内容来使此代码更清晰。我使用的是 C# 4.0,因此我无法使用该功能。
WPF Rocks。只需将我的代码复制并粘贴到 File -> New Project -> WPF Application 中,然后自己查看结果。
如果您需要进一步的帮助,请告诉我。