如何在显示进度条的同时异步地将用户控件加载到堆栈面板中

本文关键字:加载 控件 用户 堆栈 异步 显示 | 更新日期: 2023-09-27 18:24:40

我正在使用C#开发一个WPF应用程序。

我正试图了解异步线程和任务等。

基本上,我有一个用户控件,我把它添加到页面的堆栈面板中。可以将此用户控件的多次迭代添加到stackpanel中。

i.txtItemDescription.Text = "Item description " + ii.ToString() + ". Put a description here";
i.txtItemTitle.Text = "Item title " + ii.ToString() + ". Put a title here";
MainStack.Children.Add(i);

这很好用。然而,当我把这个应用程序转移到我的windows 8.1平板电脑上时,它会显著降低这些用户控件(UC)的显示速度。

我尝试过使用虚拟化,但没有效果,因为UC的数据访问和生成不会对性能产生影响。它是屏幕上控件的物理绘图。

所以我的问题如下:

  1. 在后台线程上运行此程序有助于提高性能吗
  2. 如果是这样的话,究竟是如何用BeginInvoke或Tasks加载堆栈面板的?我几乎尝试了这个网站上提到的每一个答案,要么我得到了STA错误,要么它根本没有达到我想要的效果
  3. 我对第2点的想法是,我想在表单上显示一个等待进度条(IsIndefinite=true),直到堆栈面板加载完成。但我完全被难住了。在所有情况下,表单UI都不会更新进度条,直到堆叠面板完全加载之后。在这种情况下已经太晚了

如有任何想法,我们将不胜感激!

Regds

Paul

如何在显示进度条的同时异步地将用户控件加载到堆栈面板中

首先,您不能在与最终呈现UI元素的线程不同的线程上创建UI元素,所以请忘记这种可能性。

如果是控件的物理绘制导致了性能问题,那么您可能没有正确使用UI虚拟化。UI虚拟化的全部目的是只对那些实际在视图中的控件执行布局和渲染,这意味着让某种项目(如ItemsControl)根据需要生成相应的UI元素。预先填充整个面板会破坏目的,而且常规的StackPanel无论如何都不支持虚拟化。我建议如下:

  1. 与其直接使用StackPanel,不如使用其ItemsPanelTemplate中包含VirtualizingStackPanelItemsControl

  2. 与其手动添加用户控件,不如将ItemsSource绑定到项目的底层列表,并让ItemsControl在项目进入视图时为其生成容器。

  3. 使用ItemTemplate来定义项目的呈现方式,例如,模板内容应该是具有适当绑定的用户控件。

您可以在VirtualizingStackPanel上尝试启用容器回收;根据您的使用情况,它可能有助于性能,也可能会影响性能。

无论如何,如果你遵循这个建议,你不应该需要进度指示器,因为你的项目的UI元素将在需要时生成,也就是说,当它们滚动到视图中时。


如果您以前从未将虚拟化与普通的旧ItemsControl一起使用过(默认样式不支持它),那么您可以使用下面的样式作为起点。请注意,与默认的ItemsControl样式不同,它支持滚动。

<Style TargetType="{x:Type ItemsControl}">
  <Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
          Value="Auto" />
  <Setter Property="ScrollViewer.VerticalScrollBarVisibility"
          Value="Auto" />
  <Setter Property="ScrollViewer.CanContentScroll"
          Value="True" />
  <Setter Property="ScrollViewer.PanningMode"
          Value="Both" />
  <Setter Property="Stylus.IsFlicksEnabled"
          Value="False" />
  <Setter Property="VerticalContentAlignment"
          Value="Center" />
  <Setter Property="VirtualizingStackPanel.IsVirtualizing"
          Value="True" />
  <Setter Property="VirtualizingStackPanel.VirtualizationMode"
          Value="Recycling" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ItemsControl}">
        <Border x:Name="OuterBorder"
                Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}"
                SnapsToDevicePixels="True">
          <ScrollViewer Padding="{TemplateBinding Padding}"
                        Focusable="False">
            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
          </ScrollViewer>
        </Border>
        <ControlTemplate.Triggers>
          <Trigger Property="IsEnabled"
                   Value="False">
            <Setter TargetName="OuterBorder"
                    Property="Background"
                    Value="{DynamicResource {x:Static apthemes:AssetResourceKeys.ListBackgroundDisabledBrushKey}}" />
          </Trigger>
          <Trigger Property="IsGrouping"
                   Value="True">
            <Setter Property="ScrollViewer.CanContentScroll"
                    Value="False" />
          </Trigger>
        </ControlTemplate.Triggers>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
  <Style.Triggers>
    <Trigger Property="VirtualizingStackPanel.IsVirtualizing"
             Value="True">
      <Setter Property="ItemsPanel">
        <Setter.Value>
          <ItemsPanelTemplate>
            <VirtualizingStackPanel />
          </ItemsPanelTemplate>
        </Setter.Value>
      </Setter>
    </Trigger>
  </Style.Triggers>
</Style>