Как асинхронно загружать пользовательские элементы управления в панель стека при отображении индикатора выполнения

Я разрабатываю приложение WPF с использованием C#.

Я пытаюсь разобраться с асинхронными потоками, задачами и т. Д.

В основном у меня есть usercontrol, который я добавляю в панель стека на своей странице. Может быть много итераций этого пользовательского контроля, добавленного к панели стека.

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) в форме до тех пор, пока не будет загружена панель стека. Но я в полном недоумении. Во всех случаях пользовательский интерфейс форм не обновляет индикатор выполнения до тех пор, пока панель стека не будет полностью загружена. В этом случае уже слишком поздно.

Любые мысли о том, как будут оценены!

Regds

Павел

1 ответ

Решение

Во-первых, вы не можете создавать элементы пользовательского интерфейса в другом потоке, отличном от того, в котором они в конечном итоге будут отображаться, поэтому забудьте об этой возможности.

Если физическое рисование элементов управления вызывает проблемы с производительностью, то, вероятно, вы неправильно используете виртуализацию пользовательского интерфейса. Весь смысл виртуализации пользовательского интерфейса состоит в том, чтобы выполнять макет и рендеринг только для тех элементов управления, которые на самом деле находятся в поле зрения, что означает предоставление некоторого вида элементов размещения (например, ItemsControl) генерировать соответствующие элементы пользовательского интерфейса по мере необходимости. Предварительное заполнение всей панели побеждает цель, а регулярный StackPanel В любом случае не поддерживает виртуализацию. Я предлагаю следующее:

  1. Вместо использования StackPanel напрямую, используйте ItemsControl с VirtualizingStackPanel в его ItemsPanelTemplate,

  2. Вместо добавления пользовательских элементов управления вручную, свяжите ItemsSource к основному списку предметов, и пусть ItemsControl генерировать контейнеры для элементов по мере их появления.

  3. Используйте ItemTemplate чтобы определить, как элементы отображаются, например, содержимое шаблона должно быть вашим пользовательским контролем с соответствующими привязками.

Вы можете поэкспериментировать с включением утилизации контейнеров на VirtualizingStackPanel; в зависимости от вашего варианта использования это может помочь или снизить производительность.

В любом случае, если вы будете следовать этому совету, вам не понадобится индикатор прогресса, поскольку элементы пользовательского интерфейса для ваших элементов будут сгенерированы по мере необходимости, т. Е. Когда они прокручиваются в поле зрения.


Если вы никогда не использовали виртуализацию с простым старым 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>
Другие вопросы по тегам