Как добавить триггер события в шаблон данных для бизнес-объекта?
-
07-07-2019 - |
Вопрос
У меня есть собственный класс с именем BlinkingLight. У меня также есть статическая ObservableCollection BlinkingLightCollection. В пользовательском интерфейсе у меня есть ListBox, который связан с BlinkingLightCollection.
В своем ListBox я хочу по существу отобразить каждый объект BlinkingLight в виде пользовательского элемента управления, который выглядит как блок со светодиодной подсветкой, которая имеет анимацию, которая заставляет светодиод выглядеть так, как будто он просто мигает на секунду, а затем возвращается в нормальное состояние. р>
В моем классе BlinkingLight есть сторонний индикатор "LED" объект, который вызывает событие под названием «Flash».
Я ищу идеи или решения, чтобы заставить это работать!
Моя неудачная попытка:
Я создал пользовательский элемент управления (BlinkingLightControl), который может связываться с данными моего класса BlinkingLight, когда BlinkingLight является DataContext моего настраиваемого элемента управления.
Я создал DataTemplate для моего ListBox:
<Window.Resources>
<DataTemplate x:Key="blinkingLightItemTemplate" >
<local:BlinkingLightControl />
</DataTemplate>
</Window.Resources>
<ListBox ItemsSource={Binding Source={x:Static local:Data.BlinkingLightCollection}}
ItemTemplate="{StaticResource blinkingLightItemTemplate}" />
Примечание. Я могу просто поместить xaml для своего пользовательского элемента управления в табличку с данными, вместо этого имея совершенно другой элемент управления, если это облегчает задачу.
Теперь я хочу, чтобы в моем BlinkingLightControl (или DataTemplate) был EventTrigger, для которого RoutedEvent является событием LED.Flash. К сожалению, я не могу понять эту часть. Я попытался создать RoutedEvent в своем классе BlinkingLight и просто вызывать его всякий раз, когда я обрабатываю событие LED.Flash. Однако мой класс не UIElement или ContentElement, а для каждого MSDN: Ссылка MSND а> р>
" Владелец перенаправленного события может быть любым классом, но перенаправленные события должны вызываться и обрабатываться производными классами UIElement или ContentElement, чтобы быть полезными. Дополнительную информацию о пользовательских событиях см. В разделе Как создать пользовательское перенаправленное событие. & Quot; Любая помощь будет принята с благодарностью!
Спасибо,
Скотт
Решение 2
Мне удалось найти решение, которое работало достаточно хорошо:
Поскольку мой DataTemplate просто содержит пользовательский UserControl (который привязывается к DataContext для получения его данных из бизнес-объекта) ... я поместил свой пользовательский RoutedEvent в UserControl. Затем в загруженном событии моего UserControl я приводил DataContext в качестве моего бизнес-объекта, чтобы получить доступ к свойству бизнес-объекта, в котором есть событие, и подключил его к обработчику события. (в моем примере я приводил DataContext как объект BlinkingLight, затем я могу получить доступ к событию Flash его свойства Led и подключить его к пользовательскому обработчику событий). Примечание. Объект LED должен быть свойством, а не просто полем в объекте BlinkingLight, чтобы он работал.
Затем обработчик события может вызвать пользовательское перенаправленное событие UserControl (FlashGreenEvent). Ниже приведен внутренний код, который теперь дополняет код в OP (я удалил любой другой не относящийся к делу код).
public partial class BlinkingLightControl : UserControl
{
public static readonly RoutedEvent FlashGreenEvent = EventManager.RegisterRoutedEvent("FlashGreen", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(BlinkingLightControl));
public event RoutedEventHandler FlashGreen
{
add { AddHandler(FlashGreenEvent, value); }
remove { RemoveHandler(FlashGreenEvent, value); }
}
private void BlinkingLightControl_Loaded(object sender, RoutedEventArgs e)
{
BlinkingLight blinkingLight = (BlinkingLight)this.DataContext;
blinkingLight.Led.Flash += LED_Flash;
}
protected delegate void LED_FlashCallback(ThirdParty.LED sender);
public void LED_Flash(ThirdParty.LED sender)
{
if (this.Dispatcher.CheckAccess())
{
// Raise the Flash Green Event;
RaiseEvent(new RoutedEventArgs(BlinkingLightControl.FlashGreenEvent));
}
else
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new LED_FlashCallback(LED_Flash), sender);
}
}
Другие советы
В этом случае лучше всего использовать командование WPF и создать " BlinkTheLights " RoutedCommand - ваш BlinkingLightControl обработает команду BlinkTheLights и ответит, запустив StoryBoard, которая будет мигать. Р>
Если вы создаете пользовательский элемент управления, вы всегда можете установить триггер за пределами шаблона элемента управления. Р>
что-то вроде:
<Style TargetType="{x:Type local:MyControl}">
<!-- fade in the control with an animation -->
<Style.Triggers>
<EventTrigger RoutedEvent="Control.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="1" Duration="0:0:1" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
<!-- Make sure the opacity starts at 0 -->
<Setter Property="Opacity" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyControl}">
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>