How do I add an event trigger to the data template for a business object?

I have a custom class named BlinkingLight. I also have a static ObservableCollection BlinkingLightCollection. In the UI, I have a ListBox associated with a BlinkingLightCollection.

In my ListBox, I want to essentially render each BlinkingLight object as a custom control that looks like a box with an LED indicator that has an animation that makes the LED look like it blinks instantly and then returns to normal.

My BlinkingLight class has a third party "LED" object that raises an event called "Flash".

I'm looking for ideas or solutions to get this to work!

My failed attempt:

I've created a custom control (BlinkingLightControl) that can bind to the data of my BlinkingLight class when BlinkingLight is the DataContext of my custom control.

I created a DataTemplate for my ListBox:

<Window.Resources>
  <DataTemplate x:Key="blinkingLightItemTemplate" >
    <local:BlinkingLightControl />
  </DataTemplate>
</Window.Resources>

<ListBox ItemsSource={Binding Source={x:Static local:Data.BlinkingLightCollection}}
         ItemTemplate="{StaticResource blinkingLightItemTemplate}" />

      

Note. I can just put the xaml for my custom control in the datatemplate, instead having a completely different control if that makes things easier.

Now I want to have an EventTrigger in my BlinkingLightControl (or DataTemplate), which RoutedEvent is an LED.Flash event. Unfortunately, I cannot imagine this part. I tried to create a RoutedEvent in my BlinkingLight class and just raise it whenever I handle the LED.Flash event. However my class is not a UIElement or ContentElement, but for MSDN: MSND Link

"The owner of a routed event can be any class, but routed events must be raised and handled by derived classes UIElement or ContentElement to be useful. For more information on custom events, see How to: Create a Custom Routed Event."

Any help would be greatly appreciated !! Thanks, Scott

+2


source to share


3 answers


I was able to come up with a solution that worked pretty well:

Since my DataTemplate just contains a custom UserControl (which binds to the DataContext to get its data from the business object) ... I put my custom RoutedEvent in the UserControl. Then, in my loaded UserControl event, I passed the DataContext as my business object to access the property of the business object that has the event and connect it to the event handler. (in my example, I passed the DataContext as a BlinkingLight object, then I can access its Led event event and hook it up to a custom event handler). Note. The LED object must be a property, not just a field of the BlinkingLight object for it to work.



The event handler can then raise a custom UserControl routed event (FlashGreenEvent). Below is the end-of-code code that now complements the code in the OP (I've removed any other irrelevant code).

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);
    }
}

      

+2


source


In this case, your best bet is to use WPF Commanding and create a "RoutingCommand" BlinkTheLights - your BlinkingLightControl will process the BlinkTheLights command and respond by launching a StoryBoard that is blinking.



+2


source


If you are creating a custom control, you can always set the trigger outside of the control template.

something like:

  <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>

      

+1


source







All Articles