有没有办法延迟WPF DataBinding(改进渲染)?

Jer*_*xon 6 data-binding wpf animation storyboard

这是我的问题.

ListBox A显示Observable Collection中的所有项目.

ListBox B仅显示在ListBox A中选择的项目.

    <ListBox ItemsSource="{Binding MyView}" Name="ListBoxA">
    <ListBox ItemsSource="{Binding Path=SelectedItems, 
        ElementName=ListBoxA}" Name="ListBoxB">
Run Code Online (Sandbox Code Playgroud)

在ListBox A中更改选择时,将运行StoryBoard.根据用户的选择,生成的UI是一个很酷且平滑的进出ListBox B的幻灯片.

问题是,我的ListBox A数据绑定只有Name属性,ListBox B数据绑定数十个,在某些情况下甚至数百个属性.

问题仍在继续,WPF中的数据绑定在渲染时会产生50-500毫秒的短暂UI延迟(特别是在它具有动态性时).用户界面冻结了.

这是可以忍受的.但我的StoryBoard似乎被这个DataBinding延迟阻止了.因此,用户界面"快照"到位,我看不到流畅的StoryBoard.

我通过附加到StoryBoard.Completed事件解决了这个问题.一旦StoryBoard完成,我就为ListBox B设置ItemsSource.

然而,这只有50%不错.用户看到StoryBoard执行,是的.但是,动画之后,ListBox B的结果UI仍然"捕捉"到视图中.

在我看来,正确的解决方案是以某种方式指示ListBox B内呈现的控件等待,或延迟实际的数据绑定.这将允许UI被渲染并参与StoryBoard - 但是数据将在以后"填充"(希望还能延迟DataBinding引起的延迟).

有人有过类似的问题吗?

这是完全演示问题的XAML(因为StackOverflow限制了问题的大小,您需要添加额外的TextBox才能真正看到延迟):

<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>
Run Code Online (Sandbox Code Playgroud)

看起来像这样:

在此输入图像描述

谢谢!

Jer*_*xon 0

除了最小化结果控件中可见元素的数量之外,没有其他方法可以处理此问题。当然,您也可以购买更大的电脑,但这只是开玩笑。