The issue I am having is that when I begin a storyboard, it changes the value in the object as expected, but there is no visible animation. Nothing happens while the storyboard is running, then when it's done, the object will instantly take the final result of the storyboard (using HoldEnd
). The duration of the storyboard basically acts like a delay.
Scrollviewer
with a Stackpanel
to display a list of
animated custom-user-controls. These items are 28 pixels high, and
contain buttons to expand and collapse sections holding data. MainWindow
and
added to the Scrollviewer
using scrData.Dispatcher.Invoke(()=>{})
.I suspect the problem could be the thread which owns these controls. Since they're created in the Scrollviewer
's dispatcher method, does that mean the UI thread owns them, or the thread which fired the event owns them?
I have used basically the same code to animate things before, so the only real difference is that these controls were created at run-time.
Any help will be appreciated :)
Here is the relevant bits of my code:
MainWindow.cs: (receive data, make item):
private void DataPoller_Update(object sender, DataPollerEventArgs e)
{
//New Data arrives here
if (e.message == "results")
{
DisplayData(e.data);
}
}
public void DisplayData(List<DataItem> data){
scrData.Dispatcher.Invoke(() => {
int i = 0;
foreach (DataItem item in data) {
if (IsInCurrentList(item.id)) {
Update_ExistingItemInfo(item);
}
else {
//Add new item to StackPanel
CustomControls.data_item newItem = new CustomControls.data_item(item);
stkData.Children.Insert(i, newItem);
}
i++;
}
}
}
From The UserControl's .cs:
DataItem data;
public data_item(DataItem newData)
{
InitializeComponent();
data = newData;
PopulateDataFields();
//THESE ROWS SHOULD EXPAND OR COLLAPSE ON btnExpand_Click
grdMain.RowDefinitions[1].Height = new GridLength(0);
grdMain.RowDefinitions[2].Height = new GridLength(0);
}
private void btnExpand_Click(object sender, RoutedEventArgs e)
{
//For some reason, can't find reference to sb_Expand directly.
btnExpand.Dispatcher.Invoke(()=> {
if (rowDrilldown.ActualHeight > 0) {
Storyboard sb = (Storyboard)this.Resources["sb_Collapse"];
sb.Begin();
}
else {
Storyboard sb = (Storyboard)this.Resources["sb_Expand"];
sb.Begin();
}
});
}
From the UserControl's xaml:
<UserControl.Resources>
<Storyboard x:Key="sb_Expand">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(RowDefinition.Height)" Storyboard.TargetName="rowDrilldown" BeginTime="0" FillBehavior="HoldEnd">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<GridLength>0</GridLength>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.25">
<DiscreteObjectKeyFrame.Value>
<GridLength>400</GridLength>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="sb_Collapse">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(RowDefinition.Height)" Storyboard.TargetName="rowDrilldown" BeginTime="0" FillBehavior="HoldEnd">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<GridLength>400</GridLength>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.25">
<DiscreteObjectKeyFrame.Value>
<GridLength>0</GridLength>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<Border BorderBrush="AliceBlue" BorderThickness="1" CornerRadius="4">
<Grid x:Name="grdMain">
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition Height="165"/>
<RowDefinition x:Name="rowDrilldown" Height="400"/>
</Grid.RowDefinitions>
<!--Textboxes and other CustomControls-->
</Grid>
</Border>
Found an easier way to do it using VisualStateManager:
<Storyboard x:Key="sb_Expand">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Height" Storyboard.TargetName="scrDrilldown" FillBehavior="HoldEnd">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="390"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
.
<Grid x:Name="grdMain">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="grdMain_VSG">
<VisualState x:Name="ExpandItem" Storyboard="{StaticResource sb_Expand}"/>
<VisualState x:Name="CollapseItem" Storyboard="{StaticResource sb_Collapse}"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
//on button click:
bool tmp = ExtendedVisualStateManager.GoToElementState(this.grdMain as FrameworkElement, "ExpandItem", true);