Here’s my problem.
ListBox A show all the items in an Observable Collection.
ListBox B shows only those items selected in ListBox A.
<ListBox ItemsSource="{Binding MyView}" Name="ListBoxA">
<ListBox ItemsSource="{Binding Path=SelectedItems,
ElementName=ListBoxA}" Name="ListBoxB">
When the selection is changed in ListBox A, a StoryBoard runs. The resulting UI is a cool and smooth slide in and out of ListBox B based on the user’s selection.
The problem is, where my ListBox A databinds only the Name property, ListBox B databinds dozens and in some cases even hundreds of properties.
The problem continues in that databinding in WPF creates a short, 50-500 millisecond UI delay when it is rendering (specifically when it is dynamnic). The UI freezes.
This is tollerable. But my StoryBoard seems to be blocked by this DataBinding delay. As a result the UI sort of “snaps” into place and my smooth StoryBoard isn’t seen.
I have resolved this by attaching to the StoryBoard.Completed event. Once the StoryBoard is complete, then I set the ItemsSource for ListBox B.
However, this is only 50% nice. The user sees the StoryBoard execute, yes. But the resulting UI of ListBox B still “snaps” into view after the animation.
It seems to me that the correct resolution is to somehow indicate to the controls rendered inside ListBox B to wait, or delay the actual databinding. This would allow the UI to be rendered and participate in the StoryBoard – but the data to “fill in” later (hopefully also delaying the delay caused by the DataBinding).
Has anyone had a similar problem?
Here’s the XAML that demonstrates the problem exactly (because StackOverflow limits the size of a question, you will need to add additional TextBoxes to really see the delay significantly):
<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>
Looks like this:

Thanks!
There is no way to handle this except to minimize the number of visible elements in the resulting control. Of course, you can also buy a bigger PC but that’s only kidding.