为运行时创建的 CustomUserControl 设置动画
Animating a CustomUserControl created at runtime
我遇到的问题是,当我开始故事板时,它会按预期更改对象中的值,但没有可见的动画。故事板 运行ning 时什么也没有发生,然后当它完成时,对象将立即获取故事板的最终结果(使用 HoldEnd
)。故事板的持续时间基本上就像一个延迟。
- 我正在使用
Scrollviewer
和 Stackpanel
来显示列表
动画自定义用户控件。这些项目是 28 像素高,并且
包含用于展开和折叠保存数据的部分的按钮。
- 当在我的
MainWindow
中收到事件时创建项目并且
使用 scrData.Dispatcher.Invoke(()=>{})
添加到 Scrollviewer
。
我怀疑问题可能出在拥有这些控件的线程上。由于它们是在 Scrollviewer
的调度程序方法中创建的,这是否意味着 UI 线程拥有它们,或者触发事件的线程拥有它们?
我以前使用过基本相同的代码来制作动画,所以唯一真正的区别是这些控件是在 运行 时间创建的。
任何帮助将不胜感激:)
这是我的代码的相关部分:
MainWindow.cs:(接收数据,制作物品):
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++;
}
}
}
来自 UserControl 的 .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();
}
});
}
来自用户控件的 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>
使用 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>
//点击按钮:
bool tmp = ExtendedVisualStateManager.GoToElementState(this.grdMain as FrameworkElement, "ExpandItem", true);
我遇到的问题是,当我开始故事板时,它会按预期更改对象中的值,但没有可见的动画。故事板 运行ning 时什么也没有发生,然后当它完成时,对象将立即获取故事板的最终结果(使用 HoldEnd
)。故事板的持续时间基本上就像一个延迟。
- 我正在使用
Scrollviewer
和Stackpanel
来显示列表 动画自定义用户控件。这些项目是 28 像素高,并且 包含用于展开和折叠保存数据的部分的按钮。 - 当在我的
MainWindow
中收到事件时创建项目并且 使用scrData.Dispatcher.Invoke(()=>{})
添加到Scrollviewer
。
我怀疑问题可能出在拥有这些控件的线程上。由于它们是在 Scrollviewer
的调度程序方法中创建的,这是否意味着 UI 线程拥有它们,或者触发事件的线程拥有它们?
我以前使用过基本相同的代码来制作动画,所以唯一真正的区别是这些控件是在 运行 时间创建的。
任何帮助将不胜感激:)
这是我的代码的相关部分:
MainWindow.cs:(接收数据,制作物品):
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++;
}
}
}
来自 UserControl 的 .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();
}
});
}
来自用户控件的 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>
使用 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>
//点击按钮:
bool tmp = ExtendedVisualStateManager.GoToElementState(this.grdMain as FrameworkElement, "ExpandItem", true);