Как добавить триггер события в шаблон данных для бизнес-объекта?

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

Вопрос

У меня есть собственный класс с именем 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>
scroll top