简体   繁体   English

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

[英]How to load usercontrols into a stackpanel asynchronously whilst showing progress bar

I am developing a WPF appl using C#. 我正在使用C#开发WPF应用程序。

I am trying to get my head around the async threading and tasks etc. 我试图让我的头脑异步线程和任务等。

Basically I have a usercontrol, that i add to a stackpanel in my page. 基本上我有一个用户控件,我将其添加到页面的堆栈面板中。 There can be many iterations of this usercontrol added to the 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);

This works fine. 这很好。 However, when i transfer this appl to my windows 8.1 tablet it slows the display of these usercontrols(UCs) down dramatically. 但是,当我将此应用程序转移到Windows 8.1平板电脑时,它们会大大降低这些usercontrols(UCs)的显示速度。

I have tried using virtulization which had no effect as the data access and generation of the UCs poses no performance impact. 我尝试过使用虚拟化,因为数据访问和UC的生成对性能没有影响,因此虚拟化没有效果。 It is the physical drawing of the controls on the screen. 它是屏幕上控件的物理图。

So my question is as follows: 所以我的问题如下:

  1. Would running this on a background thread help performance? 在后台线程上运行此程序会提高性能吗?
  2. If so, how on earth does one load the stackpanel with BeginInvoke or Tasks? 如果是这样,到底如何用BeginInvoke或Tasks加载堆栈面板? I have tried almost every answer mentioned on this site and either I get an STA error or it simply does not do what I would like. 我已经尝试了该站点上提到的几乎所有答案,但是我遇到了STA错误,或者它根本无法满足我的要求。
  3. My thoughts behind point 2 is that I would like to show a wait progress bar (IsIndefinite=true) on the form until such time as the stackpanel has finished loaded. 我在第2点后面的想法是,我想在窗体上显示一个等待进度栏(IsIndefinite = true),直到堆栈面板完成加载为止。 But I'm totally stumped. 但是我完全被困住了。 In all cases the forms UI does not update the progress bar until after the stackpanel has fully loaded. 在所有情况下,直到完全加载堆栈面板后,表单UI才会更新进度栏。 In which case it is too late. 在这种情况下为时已晚。

Any thoughts on how to would be appreciated! 关于如何的任何想法将不胜感激!

Regds Regds

Paul 保罗

First, you cannot create UI elements on a different thread than the one they will ultimately be rendered on, so forget about that possibility. 首先,您不能在与最终呈现它们的线程不同的线程上创建UI元素,因此请不要考虑这种可能性。

If it is the physical drawing of the controls that is causing performance problems, then you are probably not using UI virtualization correctly. 如果是导致性能问题的控件的物理绘图,则可能是您没有正确使用UI虚拟化。 The whole point of UI virtualization is to only perform layout and rendering for those controls which are actually in view, which means letting some sort of items host (like an ItemsControl ) generate the corresponding UI elements as needed. UI虚拟化的全部目的是仅对那些实际在视图中的控件执行布局和渲染,这意味着让某种项目宿主(如ItemsControl )根据需要生成相应的UI元素。 Pre-populating the entire panel defeats the purpose, and a regular StackPanel does not support virtualization anyway. 预先填充整个面板无法达到目的,常规的StackPanel仍然不支持虚拟化。 I suggest the following: 我建议以下内容:

  1. Instead of using a StackPanel directly, use an ItemsControl with a VirtualizingStackPanel in its ItemsPanelTemplate . 而不是使用的StackPanel直接使用ItemsControlVirtualizingStackPanel在其ItemsPanelTemplate

  2. Instead of adding the user controls manually, bind the ItemsSource to the underlying list of items, and let the ItemsControl generate containers for the items as they are brought into view. 与其手动添加用户控件,不如将ItemsSource绑定到项目的基础列表,并让ItemsControl为项目生成容器,使它们进入视图。

  3. Use an ItemTemplate to define how the items are rendered, eg, the template content should be your user control with the appropriate bindings. 使用ItemTemplate定义项目的呈现方式,例如,模板内容应是具有适当绑定的用户控件。

You can experiment with enabling container recycling on the VirtualizingStackPanel ; 您可以尝试在VirtualizingStackPanel上启用容器回收; depending on your use case, it may help or hurt performance. 根据您的用例,它可能会帮助或损害性能。

Anyway, if you follow this advice, you should not need a progress indicator, as the UI elements for your items will be generated as they are are needed, ie, as they are scrolled into view. 无论如何,如果您遵循此建议,则不需要进度指示器,因为将根据需要生成项目的UI元素,即当它们滚动到视图中时。


If you've never used virtualization with a plain old ItemsControl before (the default style does not support it), you can use the style below as a starting point. 如果您以前从未使用过带有简单的旧ItemsControl虚拟化(默认样式不支持它),则可以使用以下样式作为起点。 Note that it supports scrolling, unlike the default ItemsControl style. 请注意,它支持滚动,这与默认的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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM