【发布时间】:2013-03-11 09:46:44
【问题描述】:
我们有一个使用 MVVM 模式编写的 WPF 应用程序。应用程序中有一个 TabControl,每个选项卡中都有不同的 UserControl。在某些情况下,选项卡上的用户控件之一在切换到包含选项卡时可能需要很长时间才能加载。
这不是因为 ViewModel 中存在任何性能瓶颈。但相反,这是由于用户控件需要花费大量时间来绑定到 ViewModel,并创建其中包含的各种 UI 元素并对其进行初始化。
当用户单击此用户控件的选项卡时,UI 将完全无响应,直到控件完成加载。事实上,在加载所有内容之前,您甚至都看不到“活动选项卡”开关。
在等待 UI 元素完成加载时,我可以使用哪些策略来显示带有某种“请稍候,正在加载...”消息的“微调器”?
更新示例代码:
下面演示了我试图解决的问题类型。当您单击“慢速选项卡”时。在慢速选项卡中的所有项目都呈现之前,UI 变得无响应。
在下面,TestVM 是慢速选项卡的视图模型。它有大量的子对象。每个都使用自己的数据模板创建。
如何在慢速标签完成加载时显示“正在加载”消息?
public class MainVM
{
private TestVM _testVM = new TestVM();
public TestVM TestVM
{
get { return _testVM; }
}
}
/// <summary>
/// TestVM is the ViewModel for the 'slow tab'. It contains a large collection of children objects that each will use a datatemplate to render.
/// </summary>
public class TestVM
{
private IEnumerable<ChildBase> _children;
public TestVM()
{
List<ChildBase> list = new List<ChildBase>();
for (int i = 0; i < 100; i++)
{
if (i % 3 == 0)
{
list.Add(new Child1());
}
else if (i % 3 == 1)
{
list.Add(new Child2());
}
else
{
list.Add(new Child3());
}
}
_children = list;
}
public IEnumerable<ChildBase> Children
{
get { return _children; }
}
}
/// <summary>
/// Just a base class for a randomly positioned VM
/// </summary>
public abstract class ChildBase
{
private static Random _rand = new Random(1);
private int _top = _rand.Next(800);
private int _left = _rand.Next(800);
public int Top { get { return _top; } }
public int Left { get { return _left; } }
}
public class Child1 : ChildBase { }
public class Child2 : ChildBase { }
public class Child3 : ChildBase { }
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication3"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<!-- Template for the slow loading tab -->
<DataTemplate DataType="{x:Type local:TestVM}">
<ItemsControl ItemsSource="{Binding Children}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True"></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="FrameworkElement">
<Setter Property="Canvas.Top" Value="{Binding Top}"></Setter>
<Setter Property="Canvas.Left" Value="{Binding Left}"></Setter>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</DataTemplate>
<!-- examples of different child templates contained in the slow rendering tab -->
<DataTemplate DataType="{x:Type local:Child1}">
<DataGrid></DataGrid><!--simply an example of a complex control-->
</DataTemplate>
<DataTemplate DataType="{x:Type local:Child2}">
<RichTextBox Width="30" Height="30">
<!--simply an example of a complex control-->
</RichTextBox>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Child3}">
<Calendar Height="10" Width="15"></Calendar>
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="Fast Loading tab">
<TextBlock Text="Not Much Here"></TextBlock>
</TabItem>
<TabItem Header="Slow Tab">
<ContentControl Content="{Binding TestVM}"></ContentControl>
</TabItem>
</TabControl>
</Grid>
</Window>
【问题讨论】:
-
使用Task
和Dispatcher.BeginInvoke(),这样行吗? -
如果我在同一个句子中听到
TabControl、Binding和 slow tabs 这两个词,这让我想起 TabControls 的方式存在问题当您将其绑定到 ItemsSource 时,它会尝试优化自身。通常您可以通过修复模板来解决速度问题。如果您有兴趣,请尝试使用不允许 TabControl 进行优化的自定义模板进行测试。我会发布一个或两个链接...