В WPF форму, цвет заливки останавливается обновление раскадровка мигающая анимация
Мое приложение WPF-это монитор для производственных систем. В главном окне отображается один из 3 элементов управления, отображающих состояние соединения (вниз, загрузка или вверх). Элемент управления UP имеет несколько форм кнопок высокого уровня (эллипс в приведенном ниже примере), представляющих различные элементы производственной системы (маршрутизатор, конфигурация, внутренние соединения, внешние соединения и т. д.). цвет объекта отражает "худшее" состояние его детей (или внуков, или правнуков...). Он также будет мигать/мигать (через анимацию раскадровки), если один из детей изменит статус.
Каждая форма кнопки сопоставляется с объектом ColorStatus:
public class ColorStatus: INotifyPropertyChanged { private eStatusColor StatusColor {get; set;} public bool IsFlashing {get; set;} // ... }
eStatusColor перечисление (не активен, нормально, предупреждение, критическое), в котором я использую конвертер Level2Color_Converter (), чтобы изменить его к solidcolorbrush (серый/зеленый/желтый/красный), и применить его к форме заполнения. Bool IsFlashing используется для запуска анимации цвета заливки (будет переходить от текущего цвета к StatusBlinked, который является черным, а затем обратно к текущему цвету, в течение примерно 1 секунды). Вот пример формы кнопки (маршрутизатор Овальный):
<!-- Router Oval --> <Button Grid.Column="1" Margin="0,3" VerticalAlignment="Center" HorizontalAlignment="Center" Focusable="False" ToolTip="Open Router Window" Command="{Binding OpenRouterWindow_Command}" > <Button.Template> <!-- This part turns off button borders/on mouseover animations --> <ControlTemplate TargetType="Button"> <ContentPresenter Content="{TemplateBinding Content}"/> </ControlTemplate> </Button.Template> <Grid> <Ellipse HorizontalAlignment="Center" VerticalAlignment="Center" Height="60" Width="155" Stroke="Black" StrokeThickness="2" Fill="{Binding RouterStatus.StatusColor, Converter={local:Level2Color_Converter}}"> <Ellipse.Style> <Style TargetType="{x:Type Ellipse}"> <Style.Triggers> <DataTrigger Binding="{Binding RouterStatus.IsFlashing}" Value="True"> <DataTrigger.EnterActions> <BeginStoryboard Name="Router_storyboard"> <BeginStoryboard.Storyboard> <Storyboard> <ColorAnimation To="{StaticResource StatusBlinked}" Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" AutoReverse="True" RepeatBehavior="Forever" Duration="0:0:0.5"/> </Storyboard> </BeginStoryboard.Storyboard> </BeginStoryboard> </DataTrigger.EnterActions> </DataTrigger> <DataTrigger Binding="{Binding RouterStatus.IsFlashing}" Value="False"> <DataTrigger.EnterActions> <StopStoryboard BeginStoryboardName="Router_storyboard"/> </DataTrigger.EnterActions> </DataTrigger> </Style.Triggers> </Style> </Ellipse.Style> </Ellipse> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="Arial" FontSize="13" Foreground="White" Text="ROUTER"> <TextBlock.Effect> <DropShadowEffect/> </TextBlock.Effect> </TextBlock> </Grid> </Button>
Проблема в том, что если объект уже мигает и вы меняете цвет (скажем, с желтого на красный), он отключает анимацию раскадровки (даже если bool IsFlashing все еще верен).
Обратите внимание, что нет фиксированного порядка в получении статусов детей (мы получаем их в том порядке, в котором они отправляются из производственного приложения). Также обратите внимание, что это многопоточное приложение (поток чтения ставит сообщение в очередь к потоку обработчика сообщений, который обновляет ViewModel, а графический интерфейс обновляется через INotifyPropertyChanged).
Есть ли способ исправить это такая, что раскадровка, анимация продолжается, если IsFlashing является истинным, независимо от того, есть ли способ исправить это такая, что раскадровка, анимация продолжается, если IsFlashing является истинным, независимо от заполнения изменение цвета? (или не выйти из синхронизации по изменению цвета?)
Что я уже пробовал:
In manual testing (I had a test window with buttons to force color/flashing status changes), I solved this in the following way: <pre lang="c#"> if (mockup_IsBlinking) { // Toggle is blinking to keep it blinking mockup_IsBlinking = false; mockup_IsBlinking = true; }
То есть, если он мигал, выключите мигание, а затем снова включите, чтобы перезапустить анимацию.
Для реального тестирования (получения обновлений состояния из приложения, которое я отслеживаю) я изменил ColorStatus, чтобы имитировать тот же метод, изменив сеттер:
public class ColorStatus: INotifyPropertyChanged { private eStatusColor _StatusColor; public eStatusColor StatusColor { get { return _StatusColor; } set { _StatusColor = value; if (IsFlashing) { IsFlashing = false; IsFlashing = true; } } } public bool IsFlashing {get; set;} // ... }
Но, когда я подключаюсь к фактическому применению Я контроль, я поверил сплетне детей статус обновления приходят так быстро, что анимация выходит из синхронизма (мы получаем 135 детей, добавляют, как обычно, который вызывает верхнего уровня формы кнопки от неактивных в нормальных с IsFlashing=false, то фактическое ребенок статус обновления приходят в 3 обычный для предупреждения с IsFlashing=true и 27 нормальных до критических с IsFlashing=истина). Когда я запускаю монитор, ~ 1/5 времени верхний уровень мигает правильно (мигает), 4/5 времени он неверен (IsFlashing истинен, но анимация раскадровки не работает).
Gerry Schmitz
Я не вижу никакого кода "OnPropertyChanged", связанного с IsFlashing; любая привязка будет видеть его только при запуске.
Member 12606650
Я сократил эти элементы в классе ColorStatus с помощью "// ..." (а также метода ctor), но у него есть стандартные элементы INotifyPropertyChanged (иначе он не компилировался бы). Вот недостающие строки кода INotifyPropertyChanged:
публичное событие PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
protected PropertyChangedEventHandler PropertyChangedField;
общественного недействительными on свойство changed(строки наименование)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
Gerry Schmitz
Вы должны вызвать обработчик, когда хотите распознать изменение; он не срабатывает в вакууме. Вы реализовали только минимум, который ничего не дает ... кроме компиляции. "Интерфейсы" ничего не говорят о выполнении; только "крючки".
Тебе нужно почитать.
Member 12606650
В прошлом меня упрекали за слишком много кода в моих постах, поэтому я, возможно, сократил слишком много в этом посте, но код на месте.
У меня есть тестовое окно, в котором есть кнопка для поворота цвета и кнопка для переключения IsFlashing bool. Это работает в 100% случаев. Но когда я подключаюсь к системе, которую отслеживаю, она взрывает начальное состояние системы, и мы получаем ~165 обновлений за ~ 1 секунду, и это работает только ~1/5 времени. Под работой я подразумеваю, что конечный результат моего элемента верхнего уровня должен мигать, но он не мигает (хотя IsFlashing-это правда). Ручной тест работает, потому что мой щелчок не является достаточно быстрым, чтобы вывести пользовательский интерфейс из синхронизации.