TabControl 的 BusyIndi​​cator

BusyIndicator for TabControl

我正在使用具有几个 TabItem 的 TabControl。在这些 TabItems 中,有几个图表绑定到一个大数据源。因此,每次用户尝试在选项卡之间导航时,系统都会冻结几秒钟来加载选项卡的内容。此外,这些图表在系统启动后立即配置并绑定到数据。不是在用户单击选项卡时。

我想在用户等待时以透明背景显示 Loading.... 徽标。但是由于所有这些图表都是在系统启动时配置的(在 UI 出现之前),我无法在这个阶段显示 BusyIndi​​cator。似乎 UI 需要一些时间来准备这些图表,因为除了双向绑定之外没有尝试调用后端的事件。

我的 TabControl 看起来像这样:

<TabControl x:Name="TabMain"
 Grid.RowSpan="2"
 ....
 ....
 Style="{DynamicResource TabControl}">
 <TabItem x:Name=".." DataContext="{Binding Source={StaticResource Locator}}" ....>
 <TabItem x:Name=".." ....>
 ....
</TabControl>

我一直在寻找一种方法来在适当的时间显示 BusyIndi​​cator,而不必对延迟时间进行硬编码。知道如何实现吗?

你应该提供一个最小的复制品,这样试图提供帮助的人就可以在不花费数小时的情况下证明他们的代码。

您似乎没有绑定视图模型来提供您的 tabitem,但它们设置了数据上下文。

我猜是用户选择了导航。新的 tabitem 使用它的数据呈现。渲染需要时间。

tabcontrol 继承自 selector,因此具有 selectionchanged 事件。

https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.primitives.selector.selectionchanged?view=netframework-4.8

你可以解决这个问题并显示你的忙碌指示器。

private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.Source is TabControl)  // in case you have a combo or something inside it
    {
       // Make your throbber visible
    }
}

虽然这里有一个复杂的问题 - 一个最小的可重现样本再次帮助你解决问题,因为我可以检查会发生什么。但是我不能。

您可能会发现您的 UI 线程正忙于渲染那个 tabitem 而您的 throbber 没有出现。在这种情况下,您将不得不弄清楚如何延迟将数据呈现给 选择时的 tabitem。

一旦您的 tabitem 出现,您需要通过设置可见性折叠来隐藏 throbber。一种方法是推迟该过程,直到调度员不忙。

        Dispatcher.InvokeAsync(new Action(() => { // Make throbber collapse; })
            , DispatcherPriority.Background);

使用 SelectionChanged 事件并添加加载徽标,本例中为 Rectangle

XAML

<TabControl x:Name="TabMain" SelectionChanged="tabMain_SelectionChanged"
 Grid.RowSpan="2"
 ....
 ....
 Style="{DynamicResource TabControl}">
 <TabItem x:Name=".." DataContext="{Binding Source= {StaticResource Locator}}" ....>
 <TabItem x:Name=".." ....>
 ....
</TabControl>
<Rectangle x:Name="LoadingLogo" Fill = "White" Visibility="Collapsed" Opacity=0.5/>

C#

private void tabMain_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.Source is TabControl) //if this event fired from TabControl then enter
    {
            //show loading logo
            LoadingLogo.Visibility = Visibility.Visible;

            //hide the loading logo with lower priority, so that it closes after UI finished loading
            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(()=> { LoadingLogo.Visibility = Visibility.Collapsed; }));
    }
}

有关 Dispatcher.Invoke 的更多信息。

如果 Rectangle 由于 UI 加载而未显示,您可能需要使用无边框半透明 Window 作为加载徽标。