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

时间:2014-09-25 10:50:26

标签: c# wpf multithreading stackpanel begininvoke

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

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

基本上我有一个usercontrol,我将其添加到页面中的stackpanel。可以将此usercontrol的许多迭代添加到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加载stackpanel?我已经尝试了几乎所有在这个网站上提到的答案,要么我得到一个STA错误,要么根本不做我想做的事情。
  3. 我对第2点的想法是,我想在表单上显示一个等待进度条(IsIndefinite = true),直到stackpanel完成加载为止。但我完全难过了。在所有情况下,表单UI在堆栈面板完全加载之前不会更新进度条。在这种情况下,为时已晚。
  4. 有关如何欣赏的任何想法!

    Regds

1 个答案:

答案 0 :(得分:1)

首先,您不能在与最终渲染的线程不同的线程上创建UI元素,因此请忘记这种可能性。

如果是导致性能问题的控件的物理图形,那么您可能没有正确使用UI虚拟化。 UI虚拟化的重点是仅对实际处于视图中的那些控件执行布局和渲染,这意味着让某些项主机(如ItemsControl)根据需要生成相应的UI元素。预填充整个面板会使目的失败,而常规StackPanel无法支持虚拟化。我建议如下:

  1. 不要直接使用StackPanel,而是在其ItemsControl中使用VirtualizingStackPanel ItemsPanelTemplate

  2. 不是手动添加用户控件,而是将ItemsSource绑定到基础项目列表,并让ItemsControl为项目生成容器,因为它们会被带入视图。“ p>

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

  4. 您可以尝试在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>