如何仅在 DependencyProperty 更改(不是默认值)时触发动画?
How do I trigger Animation on DependencyProperty change only (not default value)?
似乎我总是被最简单的事情难倒...
我有一个带有自定义 bool DependencyProperty 'GpoModule' 的 UserControl。
默认设置为 false。
当 'GpoModule' = true 时触发 FadeIn 动画,当 'GpoModule' = false.
时触发 FadeOut 动画
我的问题是,加载控件时会触发 FadeOut 动画,我希望仅在更改 属性 时触发动画(或者至少在加载时不在默认值上)。我怀疑我可能必须定义某种事件触发器,但我希望避免这种情况。
依赖属性:
public bool GpoModule {
get { return (bool)GetValue(GpoModuleProperty); }
set { SetValue(GpoModuleProperty, value); }
}
public static readonly DependencyProperty GpoModuleProperty =
DependencyProperty.Register("GpoModule", typeof(bool),
typeof(ModuleIndicator), new UIPropertyMetadata(false));
动画:
<UserControl.Resources>
<Duration x:Key="D">0:0:0.6</Duration>
<Storyboard x:Key="SbFadeOut">
<DoubleAnimation Storyboard.TargetProperty="(FrameworkElement.Width)"
From="38" To="0"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(FrameworkElement.Height)"
From="38"
To="0"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Opacity)"
From="1"
To="0"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="SbFadeIn">
<DoubleAnimation Storyboard.TargetProperty="(FrameworkElement.Width)"
From="0" To="38"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(FrameworkElement.Height)"
From="0"
To="38"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Opacity)"
From="0"
To="1"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</UserControl.Resources>
动画元素:
<Viewbox x:Name="GpoIndicator"
VerticalAlignment="Center" HorizontalAlignment="Center"
Stretch="Fill" Width="0" Height="0">
<Grid Height="38" Width="38">
<Ellipse Height="38"
Fill="{DynamicResource App.Primary.Light}"
Stroke="{DynamicResource App.Border}" />
<TextBlock Width="38"
Height="38"
Margin="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontFamily="{DynamicResource AppFont}"
FontSize="30"
FontWeight="Bold"
Foreground="{DynamicResource ResourceKey=App.Accent.Secondary}"
Padding="0,2,0,0"
Text="G"
TextAlignment="Center"
TextWrapping="Wrap"/>
</Grid>
<Viewbox.Style>
<Style TargetType="Viewbox">
<Style.Triggers>
<DataTrigger Binding="{Binding GpoModule, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ModuleIndicator}}}"
Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="GpoIn">
<Storyboard>
<StaticResource ResourceKey="SbFadeIn" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="GpoIn" />
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding GpoModule, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ModuleIndicator}}}"
Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard Name="GpoOut">
<Storyboard>
<StaticResource ResourceKey="SbFadeOut" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="GpoOut" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Viewbox.Style>
</Viewbox>
谢谢!
编辑:我应该提到还有另外两个 'Indicator' 对象/子对象 - 'RedesignIndicator' 和 'NovellIndicator'。每个都有各自的 bool DependencyProperties。
在提出问题之前,我尝试使用多个条件。我的第一次尝试是将条件设置为 'IsLoaded' 但没有效果。
我的第二次尝试是使用另一个 Dependency 属性 'AnimationLocked',默认设置为 true,并尝试了两种变体。
一:在 属性 已更改的回调上将 AnimationLocked 设置为 false(这具有在其他子对象之一和
上触发 FadeOut 动画的副作用
二:在 UserControl.Loaded 事件(没有效果)
上将 AnimationLocked 设置为 false
您可以使用多数据触发器:
<Viewbox.Style>
<Style TargetType="Viewbox">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsLoaded}" Value="True" />
<Condition Binding="{Binding GpoModule}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterAction>
... fade in animation
</MultiDataTrigger.EnterAction>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsLoaded}" Value="True" />
<Condition Binding="{Binding GpoModule}" Value="False" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterAction>
... fade out animation
</MultiDataTrigger.EnterAction>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Viewbox.Style>
IsLoaded
是另一个依赖项 属性,它在控件 Loaded
事件处理程序中设置为 true
。
这样动画只会在IsLoaded == true
时出现。
P.S.: 不确定是否必须在控件 Unloaded
事件处理程序中设置 IsLoaded = false
。
我最终确定的解决方案是为我控件上的三个子项 'Module Indicators' 中的每一个添加一个 'AnimationLocked' bool DependencyProperty。 'AnimationLocked' 的默认值为 true 并在 'Module' bool DependencyProperty 回调中设置为 false,这确保动画被阻止,直到 属性 被第一次用户交互手动更改。我希望有一些内置的方式可以防止 'triggering' 触发默认值。这看起来很不雅,我仍然愿意接受其他建议。
UserControl 代码隐藏:
public bool GpoAnimationLocked
{
get { return (bool)GetValue(GpoAnimationLockedProperty); }
set { SetValue(GpoAnimationLockedProperty, value); }
}
public static readonly DependencyProperty GpoAnimationLockedProperty =
DependencyProperty.Register("GpoAnimationLocked", typeof(bool),
typeof(ModuleIndicator), new UIPropertyMetadata(true));
public bool GpoModule {
get { return (bool)GetValue(GpoModuleProperty); }
set { SetValue(GpoModuleProperty, value); }
}
public static readonly DependencyProperty GpoModuleProperty =
DependencyProperty.Register("GpoModule", typeof(bool),
typeof(ModuleIndicator), new UIPropertyMetadata(false, GpoSelectionPropertyChanged));
protected virtual void GpoSelectionChanged(DependencyPropertyChangedEventArgs e) {
GpoAnimationLocked = false;
}
private static void GpoSelectionPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) {
((ModuleIndicator)sender).GpoSelectionChanged(e);
}
UserControl xaml(动画的子 'indicator':
<Viewbox x:Name="GpoIndicator"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Stretch="Fill"
Width="0"
Height="0">
<Grid Height="38"
Width="38">
<Ellipse Height="38"
Fill="{DynamicResource App.Primary.Light}"
Stroke="{DynamicResource App.Border}" />
<TextBlock Width="38"
Height="38"
Margin="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontFamily="{DynamicResource AppFont}"
FontSize="30"
FontWeight="Bold"
Foreground="{DynamicResource ResourceKey=App.Accent.Secondary}"
Padding="0,2,0,0"
Text="G"
TextAlignment="Center"
TextWrapping="Wrap" />
</Grid>
<Viewbox.Style>
<Style TargetType="Viewbox">
<Style.Triggers>
<DataTrigger Binding="{Binding GpoModule, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ModuleIndicator}}}"
Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="In">
<Storyboard>
<StaticResource ResourceKey="SbFadeIn" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="In" />
</DataTrigger.ExitActions>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding GpoAnimationLocked, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ModuleIndicator}}}"
Value="False" />
<Condition Binding="{Binding GpoModule, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ModuleIndicator}}}"
Value="False" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard Name="Out">
<StaticResource ResourceKey="SbFadeOut" />
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Out" />
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Viewbox.Style>
</Viewbox>
似乎我总是被最简单的事情难倒...
我有一个带有自定义 bool DependencyProperty 'GpoModule' 的 UserControl。
默认设置为 false。
当 'GpoModule' = true 时触发 FadeIn 动画,当 'GpoModule' = false.
时触发 FadeOut 动画
我的问题是,加载控件时会触发 FadeOut 动画,我希望仅在更改 属性 时触发动画(或者至少在加载时不在默认值上)。我怀疑我可能必须定义某种事件触发器,但我希望避免这种情况。
依赖属性:
public bool GpoModule {
get { return (bool)GetValue(GpoModuleProperty); }
set { SetValue(GpoModuleProperty, value); }
}
public static readonly DependencyProperty GpoModuleProperty =
DependencyProperty.Register("GpoModule", typeof(bool),
typeof(ModuleIndicator), new UIPropertyMetadata(false));
动画:
<UserControl.Resources>
<Duration x:Key="D">0:0:0.6</Duration>
<Storyboard x:Key="SbFadeOut">
<DoubleAnimation Storyboard.TargetProperty="(FrameworkElement.Width)"
From="38" To="0"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(FrameworkElement.Height)"
From="38"
To="0"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Opacity)"
From="1"
To="0"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="SbFadeIn">
<DoubleAnimation Storyboard.TargetProperty="(FrameworkElement.Width)"
From="0" To="38"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(FrameworkElement.Height)"
From="0"
To="38"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Opacity)"
From="0"
To="1"
Duration="{StaticResource D}">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</UserControl.Resources>
动画元素:
<Viewbox x:Name="GpoIndicator"
VerticalAlignment="Center" HorizontalAlignment="Center"
Stretch="Fill" Width="0" Height="0">
<Grid Height="38" Width="38">
<Ellipse Height="38"
Fill="{DynamicResource App.Primary.Light}"
Stroke="{DynamicResource App.Border}" />
<TextBlock Width="38"
Height="38"
Margin="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontFamily="{DynamicResource AppFont}"
FontSize="30"
FontWeight="Bold"
Foreground="{DynamicResource ResourceKey=App.Accent.Secondary}"
Padding="0,2,0,0"
Text="G"
TextAlignment="Center"
TextWrapping="Wrap"/>
</Grid>
<Viewbox.Style>
<Style TargetType="Viewbox">
<Style.Triggers>
<DataTrigger Binding="{Binding GpoModule, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ModuleIndicator}}}"
Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="GpoIn">
<Storyboard>
<StaticResource ResourceKey="SbFadeIn" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="GpoIn" />
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding GpoModule, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ModuleIndicator}}}"
Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard Name="GpoOut">
<Storyboard>
<StaticResource ResourceKey="SbFadeOut" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="GpoOut" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Viewbox.Style>
</Viewbox>
谢谢!
编辑:我应该提到还有另外两个 'Indicator' 对象/子对象 - 'RedesignIndicator' 和 'NovellIndicator'。每个都有各自的 bool DependencyProperties。
在提出问题之前,我尝试使用多个条件。我的第一次尝试是将条件设置为 'IsLoaded' 但没有效果。
我的第二次尝试是使用另一个 Dependency 属性 'AnimationLocked',默认设置为 true,并尝试了两种变体。
一:在 属性 已更改的回调上将 AnimationLocked 设置为 false(这具有在其他子对象之一和
上触发 FadeOut 动画的副作用
二:在 UserControl.Loaded 事件(没有效果)
您可以使用多数据触发器:
<Viewbox.Style>
<Style TargetType="Viewbox">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsLoaded}" Value="True" />
<Condition Binding="{Binding GpoModule}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterAction>
... fade in animation
</MultiDataTrigger.EnterAction>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsLoaded}" Value="True" />
<Condition Binding="{Binding GpoModule}" Value="False" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterAction>
... fade out animation
</MultiDataTrigger.EnterAction>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Viewbox.Style>
IsLoaded
是另一个依赖项 属性,它在控件 Loaded
事件处理程序中设置为 true
。
这样动画只会在IsLoaded == true
时出现。
P.S.: 不确定是否必须在控件 Unloaded
事件处理程序中设置 IsLoaded = false
。
我最终确定的解决方案是为我控件上的三个子项 'Module Indicators' 中的每一个添加一个 'AnimationLocked' bool DependencyProperty。 'AnimationLocked' 的默认值为 true 并在 'Module' bool DependencyProperty 回调中设置为 false,这确保动画被阻止,直到 属性 被第一次用户交互手动更改。我希望有一些内置的方式可以防止 'triggering' 触发默认值。这看起来很不雅,我仍然愿意接受其他建议。
UserControl 代码隐藏:
public bool GpoAnimationLocked
{
get { return (bool)GetValue(GpoAnimationLockedProperty); }
set { SetValue(GpoAnimationLockedProperty, value); }
}
public static readonly DependencyProperty GpoAnimationLockedProperty =
DependencyProperty.Register("GpoAnimationLocked", typeof(bool),
typeof(ModuleIndicator), new UIPropertyMetadata(true));
public bool GpoModule {
get { return (bool)GetValue(GpoModuleProperty); }
set { SetValue(GpoModuleProperty, value); }
}
public static readonly DependencyProperty GpoModuleProperty =
DependencyProperty.Register("GpoModule", typeof(bool),
typeof(ModuleIndicator), new UIPropertyMetadata(false, GpoSelectionPropertyChanged));
protected virtual void GpoSelectionChanged(DependencyPropertyChangedEventArgs e) {
GpoAnimationLocked = false;
}
private static void GpoSelectionPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) {
((ModuleIndicator)sender).GpoSelectionChanged(e);
}
UserControl xaml(动画的子 'indicator':
<Viewbox x:Name="GpoIndicator"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Stretch="Fill"
Width="0"
Height="0">
<Grid Height="38"
Width="38">
<Ellipse Height="38"
Fill="{DynamicResource App.Primary.Light}"
Stroke="{DynamicResource App.Border}" />
<TextBlock Width="38"
Height="38"
Margin="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontFamily="{DynamicResource AppFont}"
FontSize="30"
FontWeight="Bold"
Foreground="{DynamicResource ResourceKey=App.Accent.Secondary}"
Padding="0,2,0,0"
Text="G"
TextAlignment="Center"
TextWrapping="Wrap" />
</Grid>
<Viewbox.Style>
<Style TargetType="Viewbox">
<Style.Triggers>
<DataTrigger Binding="{Binding GpoModule, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ModuleIndicator}}}"
Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="In">
<Storyboard>
<StaticResource ResourceKey="SbFadeIn" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="In" />
</DataTrigger.ExitActions>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding GpoAnimationLocked, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ModuleIndicator}}}"
Value="False" />
<Condition Binding="{Binding GpoModule, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ModuleIndicator}}}"
Value="False" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard Name="Out">
<StaticResource ResourceKey="SbFadeOut" />
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Out" />
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Viewbox.Style>
</Viewbox>