English 中文(简体)
WPF Expander Border Animation affects all contained controls?
原标题:

I m using a WPF Expander to display a number of analog process variables.

I want to make the expander s border glow (or flash) when one of these variables enters a warning or alarm state.

To achieve this, I m using some data triggers bound to a couple of boolean properties in my view model ( AnalogWarningActive and AnalogAlarmActive ). The data triggers kick off a storyboard that animates the expander border opacity.

The data triggers work as I d expect: the proper border colour appears and the opacity animation begins. However, there are 2 problems:

  1. The opacity of the entire expander (and all contained controls) is changing and not just the opacity of its border.

  2. When the AnalogWarningActive and AnalogAlarmActive tags return to False, the border disappears but the opactiy animation continues indefinitely (ie. the entire expander continues to fade in and out).

Here is the xaml I m using:

<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>
最佳回答

Question #1

The Opacity setting on a Visual such as Border affects that Visual and all its descendants. That is why setting Border.Opacity makes everything disappear.

You have two choices: 1. Animate the border Stroke property, or 2. Change the content to not be a descendant of Border.

Animating the Stroke property is trivial to code, but has the disadvantage that not all brushes are easily animatable to transparent and back. For example, this is difficult with gradient brushes. Also, if your borders were a variety of colors and you didn t want to go to 100% transparent there is no good way to animate the Stroke without changing the color.

Changing the content to not be a descendant of Border is very simple, and is what I would be inclined to do in most cases. Simply replace:

<Border x:Name="MyBorder" Stroke="Red" StrokeThickness="3" CornerRadius="6">
  <my:ContentHere />
</Border>

with this:

<Grid>
  <Border x:Name="MyBorder" Stroke="Red" StrokeThickness="3" Stroke="Red" CornerRadius="6">
  <Border Stroke="Transparent" StrokeThickness="3" CornerRadius="Red">
    <my:ContentHere />
  </Border>
</Grid>

Now the visible border s opacity can be animated, while the transparent one controls the layout and clipping of the child.

If you don t have any CornerRadius or other funny business, you can just set a margin on the content and forego the transparent border:

<Grid>
  <Border x:Name="MyBorder" Stroke="Red" StrokeThickness="3" />
  <my:ContentHere Margin="3" />
</Grid>

Question #2

At first glance I don t see any problem with your XAML that would cause the animation to keep running after the triggering value goes back to false, but I didn t look very closely. From what I noticed I would think it would stop the animation at the current value, not leave it running.

You might try replacing StopStoryboard with RemoveStoryboard. RemoveStoryboard should reset the animated properties back to their original values.

问题回答

暂无回答




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签