MVVM パターンを使用して記述された WPF アプリケーションがあります。アプリケーション内には、各タブ内に異なる UserControls を持つ TabControl があります。特定の条件下では、タブ上の UserControls の 1 つが含まれているタブに切り替えるときに、読み込みにかなりの時間がかかることがあります。
これは、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>