WPF 扩展器边框动画会影响所有包含的控件吗?
-
19-09-2019 - |
题
我正在使用 WPF Expander 来显示许多模拟过程变量。
当这些变量之一进入“警告”或“警报”状态时,我想让扩展器的边框“发光”(或闪烁)。
为了实现这一目标,我使用了一些绑定到视图模型中的几个布尔属性的数据触发器(“AnalogWarningActive”和“AnalogAlarmActive”)。数据触发器启动故事板,为扩展器边框不透明度设置动画。
数据触发器按我的预期工作:出现正确的边框颜色并且不透明动画开始。然而,有两个问题:
整个扩展器(以及所有包含的控件)的不透明度正在发生变化,而不仅仅是其边框的不透明度。
当 'AnalogWarningActive' 和 'AnalogAlarmActive' 标签返回 False 时,边框消失,但 opactiy 动画无限期地继续(即整个扩展器继续淡入和淡出)。
这是我正在使用的 xaml:
<SolidColorBrush x:Key="AnalogAlarmBrush" Color="#FFFF8080" />
<SolidColorBrush x:Key="AnalogWarningBrush" Color="#FFFFFF80" />
<Storyboard x:Key="AlarmBorderFlasher" AutoReverse="True" RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetProperty="(Border.Opacity)"
From="1.0" To="0.4"
Duration="0:0:0.8" />
</Storyboard>
<Expander Header="Test Data" IsExpanded="True">
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=AnalogWarningActive}" Value="True" >
<DataTrigger.EnterActions>
<BeginStoryboard Name="WarningBorderStoryboard" Storyboard="{StaticResource AlarmBorderFlasher}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="WarningBorderStoryboard" />
</DataTrigger.ExitActions>
<DataTrigger.Setters>
<Setter Property="BorderBrush" Value="{StaticResource AnalogWarningBrush}" />
<Setter Property="BorderThickness" Value="4" />
</DataTrigger.Setters>
</DataTrigger>
<DataTrigger Binding="{Binding Path=AnalogAlarmActive}" Value="True" >
<DataTrigger.EnterActions>
<BeginStoryboard Name="AlarmBorderStoryboard" Storyboard="{StaticResource AlarmBorderFlasher}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="AlarmBorderStoryboard" />
</DataTrigger.ExitActions>
<DataTrigger.Setters>
<Setter Property="BorderBrush" Value="{StaticResource AnalogAlarmBrush}" />
<Setter Property="BorderThickness" Value="4" />
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<!-- snipped the contents of the expander (a tabcontrol and a few text boxes, labels, etc)-->
</Expander>
解决方案
问题#1
视觉对象(例如边框)上的不透明度设置会影响该视觉对象及其所有后代。这就是为什么设置 Border.Opacity 会使所有内容消失。
你有两个选择:1.对边框 Stroke 属性进行动画处理,或 2。将内容更改为不是 Border 的后代。
对 Stroke 属性进行动画处理对于代码来说很简单,但缺点是并非所有画笔都可以轻松设置为透明和返回动画。例如,使用渐变画笔就很难做到这一点。另外,如果您的边框有多种颜色,并且您不想达到 100% 透明,则没有什么好方法可以在不更改颜色的情况下为描边设置动画。
将内容更改为不是 Border 的后代非常简单,这也是我在大多数情况下倾向于做的事情。只需替换:
<Border x:Name="MyBorder" Stroke="Red" StrokeThickness="3" CornerRadius="6">
<my:ContentHere />
</Border>
有了这个:
<Grid>
<Border x:Name="MyBorder" Stroke="Red" StrokeThickness="3" Stroke="Red" CornerRadius="6">
<Border Stroke="Transparent" StrokeThickness="3" CornerRadius="Red">
<my:ContentHere />
</Border>
</Grid>
现在,可见边框的不透明度可以设置动画,而透明边框则控制子项的布局和剪裁。
如果您没有任何 CornerRadius 或其他有趣的业务,您可以只在内容上设置边距并放弃透明边框:
<Grid>
<Border x:Name="MyBorder" Stroke="Red" StrokeThickness="3" />
<my:ContentHere Margin="3" />
</Grid>
问题2
乍一看,我没有发现 XAML 存在任何问题,会导致动画在触发值恢复为 false 后继续运行,但我没有仔细观察。根据我的观察,我认为它会将动画停止在当前值,而不是让它继续运行。
您可以尝试用RemoveStoryboard 替换StopStoryboard。RemoveStoryboard 应该将动画属性重置回其原始值。