Есть ли способ отложить WPF DataBinding (улучшить визуализацию)? - PullRequest
6 голосов
/ 20 июля 2011

Вот моя проблема.

ListBox A показывает все элементы в наблюдаемой коллекции.

ListBox B показывает только те элементы, которые выбраны в ListBox A.

    <ListBox ItemsSource="{Binding MyView}" Name="ListBoxA">
    <ListBox ItemsSource="{Binding Path=SelectedItems, 
        ElementName=ListBoxA}" Name="ListBoxB">

Когда выбор изменяется в ListBox A, запускается StoryBoard. Получающийся пользовательский интерфейс представляет собой плавный и плавный ввод и вывод ListBox B в зависимости от выбора пользователя.

Проблема в том, что мои данные ListBox A связывают только свойство Name, данные ListBox B связывают десятки, а в некоторых случаях даже сотни свойств.

Проблема по-прежнему заключается в том, что привязка данных в WPF создает короткую задержку пользовательского интерфейса в 50-500 миллисекунд при рендеринге (особенно когда он динамический). Пользовательский интерфейс зависает.

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

Я решил эту проблему, добавив событие StoryBoard.Completed. Когда StoryBoard завершен, я устанавливаю ItemsSource для ListBox B.

Однако это только на 50% приятнее. Пользователь видит выполнение StoryBoard, да. Но итоговый пользовательский интерфейс ListBox B все еще «защелкивается» после анимации.

Мне кажется, что правильное разрешение должно как-то указывать элементам управления, представленным внутри ListBox B, на ожидание или задержку фактической привязки данных. Это позволило бы отображать пользовательский интерфейс и участвовать в StoryBoard, но данные «заполнялись» позже (возможно, также задерживая задержку, вызванную привязкой данных).

У кого-нибудь была подобная проблема?

Вот XAML, который точно демонстрирует проблему (поскольку StackOverflow ограничивает размер вопроса, вам необходимо добавить дополнительные текстовые поля, чтобы реально увидеть задержку):

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:sys="clr-namespace:System;assembly=mscorlib"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Page.Resources>

    <x:Array Type="{x:Type sys:String}" x:Key="MyData">
      <sys:String>One</sys:String>
      <sys:String>Two</sys:String>
      <sys:String>Three</sys:String>
      <sys:String>Four</sys:String>
      <sys:String>Five</sys:String>
      <sys:String>Six</sys:String>
    </x:Array>

    <Storyboard x:Key="MyGrowStoryboard">
        <ParallelTimeline>
            <DoubleAnimation To="1" DecelerationRatio="0.5" 
        Duration="00:00:00.500" 
        Storyboard.TargetName="MyTransform" 
        Storyboard.TargetProperty="ScaleX"  />
            <DoubleAnimation To="1" DecelerationRatio="0.5" 
        Duration="00:00:00.500" 
        Storyboard.TargetName="MyTransform" 
        Storyboard.TargetProperty="ScaleY"  />
        </ParallelTimeline>
    </Storyboard>
    <Storyboard x:Key="MyShrinkStoryboard">
        <ParallelTimeline>
            <DoubleAnimation To=".1" DecelerationRatio="0.5" 
        Duration="00:00:00.500" 
        Storyboard.TargetName="MyTransform" 
        Storyboard.TargetProperty="ScaleX"  />
            <DoubleAnimation To=".1" DecelerationRatio="0.5" 
        Duration="00:00:00.500" 
        Storyboard.TargetName="MyTransform" 
        Storyboard.TargetProperty="ScaleY"  />
        </ParallelTimeline>
    </Storyboard>

  </Page.Resources>
  <StackPanel>
    <ListBox ItemsSource="{Binding Source={StaticResource MyData}}" 
    Name="ListBoxA">
      <ListBox.ItemsPanel>
          <ItemsPanelTemplate>
              <StackPanel Orientation="Vertical" />
          </ItemsPanelTemplate>
      </ListBox.ItemsPanel>
      <ListBox.ItemTemplate>
        <DataTemplate>
          <DataTemplate.Triggers>

              <!-- grow -->
              <MultiDataTrigger>
                  <MultiDataTrigger.Conditions>
                      <Condition Value="True" 
            Binding="{Binding Path=IsSelected, 
            RelativeSource={RelativeSource 
            Mode=FindAncestor, 
            AncestorType={x:Type ListBoxItem}}}" />
                  </MultiDataTrigger.Conditions>
                  <MultiDataTrigger.EnterActions>
                      <BeginStoryboard 
            Storyboard="{StaticResource MyGrowStoryboard}" />
                  </MultiDataTrigger.EnterActions>
                  <MultiDataTrigger.ExitActions>
                      <BeginStoryboard 
            Storyboard="{StaticResource MyShrinkStoryboard}" />
                  </MultiDataTrigger.ExitActions>
              </MultiDataTrigger>

              <!-- shrink -->
              <MultiDataTrigger>
                  <MultiDataTrigger.Conditions>
                      <Condition Value="False" 
            Binding="{Binding Path=IsSelected, 
            RelativeSource={RelativeSource 
            Mode=FindAncestor, 
            AncestorType={x:Type ListBoxItem}}}" />
                      <Condition Value="1" 
            Binding="{Binding Path=SelectedItems.Count, 
            RelativeSource={RelativeSource 
            Mode=FindAncestor, 
            AncestorType={x:Type ListBox}}}" />
                  </MultiDataTrigger.Conditions>
                  <MultiDataTrigger.EnterActions>
                      <BeginStoryboard 
            Storyboard="{StaticResource MyShrinkStoryboard}" />
                  </MultiDataTrigger.EnterActions>
                  <MultiDataTrigger.ExitActions>
                      <BeginStoryboard 
            Storyboard="{StaticResource MyGrowStoryboard}" />
                  </MultiDataTrigger.ExitActions>
              </MultiDataTrigger>        

          </DataTemplate.Triggers>
          <TextBlock Text="{Binding .}">
            <TextBlock.LayoutTransform>
                <ScaleTransform ScaleX="1" ScaleY="1" 
            x:Name="MyTransform"/>
            </TextBlock.LayoutTransform>
          </TextBlock>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>

    <ListBox ItemsSource="{Binding Path=SelectedItems, 
        ElementName=ListBoxA}" Name="ListBoxB">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <UniformGrid Columns="10">
            <!-- repeat this part MANY times (like 3000) ! -->
            <TextBox Text="{Binding .}" />
            <TextBox Text="{Binding .}" />
            <TextBox Text="{Binding .}" />
            <TextBox Text="{Binding .}" />
            <TextBox Text="{Binding .}" />
          </UniformGrid>
       </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
  </StackPanel>
</Page>

выглядит так:

enter image description here

Спасибо!

Ответы [ 2 ]

4 голосов
/ 20 июля 2011

У меня никогда не было подобной проблемы раньше, и, насколько мне известно, нет встроенного способа отложить привязку данных в WPF.

Я пробовал ваш код с текстовым полем 1000+ внутри ListboxB.ListboxB рендерится довольно быстро, но если вы все еще хотите сократить время рендеринга для ListboxB, вы можете попробовать добавить приведенный ниже код в ListboxB.

VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"

Это создаст только элементы управления внутри ListBoxB, которые в настоящее время видны, поэтому он улучшитсярендеринг ListBoxB.

Вы можете оформить мою статью на VirtualizingStackPanel .

Надеюсь, этот ответ поможет вам.

0 голосов
/ 01 августа 2011

Нет способа справиться с этим, кроме как минимизировать количество видимых элементов в результирующем элементе управления. Конечно, вы также можете купить ПК побольше, но это шутка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...