Анимация границ расширителя WPF влияет на все содержащиеся элементы управления?

StackOverflow https://stackoverflow.com/questions/1701865

  •  19-09-2019
  •  | 
  •  

Вопрос

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

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

Чтобы достичь этого, я использую некоторые триггеры данных, привязанные к паре логических свойств в моей модели представления ('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

Настройка непрозрачности для визуального элемента, такого как Border, влияет на этот визуальный элемент и все его потомки.Вот почему установка границы.Из-за непрозрачности все исчезает.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top