WPF エキスパンダーの境界線アニメーションは、含まれているすべてのコントロールに影響しますか?
-
19-09-2019 - |
質問
WPF エキスパンダーを使用して、多数のアナログ プロセス変数を表示しています。
これらの変数のいずれかが「警告」または「警報」状態になったときに、エキスパンダーの境界線を「光らせる」(または点滅させる) ようにしたいと考えています。
これを実現するために、ビュー モデルのいくつかのブール型プロパティ ('AnalogWarningActive' と 'AnalogAlarmActive') にバインドされたいくつかのデータ トリガーを使用しています。データ トリガーは、エキスパンダーの境界線の不透明度をアニメーション化するストーリーボードを開始します。
データトリガーは期待どおりに機能します。適切な境界線の色が表示され、不透明度のアニメーションが始まります。ただし、次の 2 つの問題があります。
境界線の不透明度だけでなく、エキスパンダー全体 (および含まれるすべてのコントロール) の不透明度も変化します。
「AnalogWarningActive」タグと「AnalogAlarmActive」タグが False に戻ると、境界線は消えますが、不透明なアニメーションは無期限に継続します。エキスパンダー全体がフェードインとフェードアウトを繰り返します)。
私が使用している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 などのビジュアルの不透明度設定は、そのビジュアルとそのすべての子孫に影響します。Border.Opacity を設定するとすべてが消えてしまうのはこのためです。
選択肢は 2 つあります。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 に戻った後もアニメーションが実行され続けるような問題は見当たりませんが、よく見ていませんでした。私が気づいたところによると、アニメーションを実行したままにするのではなく、現在の値で停止すると思います。
StopStoryboard を RemoveStoryboard に置き換えてみてください。RemoveStoryboard は、アニメーション化されたプロパティを元の値にリセットする必要があります。