WPF Expander Border Animation влияет на все содержащиеся в нем элементы управления? - PullRequest
0 голосов
/ 09 ноября 2009

Я использую WPF Expander для отображения ряда аналоговых переменных процесса.

Я хочу, чтобы рамка расширителя «светилась» (или мигала), когда одна из этих переменных входит в состояние «предупреждение» или «тревога».

Чтобы достичь этого, я использую некоторые триггеры данных, связанные с парой логических свойств в моей модели представления (AnalogWarningActive и AnalogAlarmActive). Триггеры данных запускают раскадровку, которая оживляет непрозрачность границы расширителя.

Триггеры данных работают так, как я ожидал: появляется правильный цвет границы и начинается анимация непрозрачности. Однако есть 2 проблемы:

  1. Непрозрачность всего расширителя (и всех содержащихся в нем элементов управления) изменяется, а не только непрозрачность его границы.

  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 Ответ

1 голос
/ 09 ноября 2009

Вопрос № 1

Параметр «Непрозрачность» в визуале, например «Граница», влияет на этот визуал и всех его потомков. Вот почему установка Border.Opacity заставляет все исчезать.

У вас есть два варианта: 1. Анимировать свойство border 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, из-за которых анимация будет продолжать работать после того, как значение срабатывания вернется к ложному значению, но я не очень внимательно посмотрел. Из того, что я заметил, я думаю, что это остановит анимацию при текущем значении, а не заставит ее работать.

Вы можете попробовать заменить StopStoryboard на RemoveStoryboard. RemoveStoryboard должен сбросить анимированные свойства обратно к их исходным значениям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...