Pregunta

Tengo una clase personalizada llamada BlinkingLight. También tengo una ObservableCollection BlinkingLightCollection estática. En la interfaz de usuario, tengo un ListBox que está vinculado a BlinkingLightCollection.

En mi ListBox, quiero mostrar esencialmente cada objeto BlinkingLight como un control personalizado que parece un cuadro con una luz LED que tiene una animación que hace que el LED parezca que se encendió por un segundo y luego vuelve a la normalidad.

Mi clase de Luz Parpadeante tiene un LED "de terceros" objeto que genera un evento llamado 'Flash'.

¡Estoy buscando ideas o soluciones para que esto funcione!

Mi intento fallido:

Creé un control personalizado (BlinkingLightControl) que puede unirse a los datos de mi clase BlinkingLight cuando un BlinkingLight es el DataContext de mi control personalizado.

Creé un DataTemplate para mi ListBox:

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

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

Nota: puedo poner el xaml para mi control personalizado en la plantilla de datos en lugar de tener un control completamente diferente si eso facilita las cosas.

Ahora quiero tener un EventTrigger en mi BlinkingLightControl (o DataTemplate) cuyo RoutedEvent es el evento LED.Flash. Desafortunadamente, parece que no puedo entender esta parte. Traté de crear un RoutedEvent en mi clase BlinkingLight y solo levantarlo cada vez que manejo el evento LED.Flash. Sin embargo, mi clase no es un UIElement o ContentElement, y según MSDN: MSND Link

" El propietario del evento enrutado puede ser cualquier clase, pero los eventos enrutados deben ser generados y manejados por las clases derivadas de UIElement o ContentElement para que sean útiles. Para obtener más información sobre eventos personalizados, consulte Cómo: Crear un evento enrutado personalizado. & Quot;

¡Cualquier ayuda sería muy apreciada! Gracias, Scott

¿Fue útil?

Solución 2

Pude encontrar una solución que funcionó bastante bien:

Dado que mi DataTemplate simplemente contiene un UserControl personalizado (que se une al DataContext para obtener sus datos del objeto comercial) ... coloqué mi RoutedEvent personalizado en el UserControl. Luego, en el evento cargado de mi UserControl, lanzo el DataContext como mi objeto comercial para obtener acceso a la propiedad del objeto comercial que tiene el evento y lo conecto a un controlador de eventos. (en mi ejemplo, lanzo el DataContext como un objeto BlinkingLight, entonces puedo obtener acceso al evento Flash de su propiedad Led y conectarlo a un controlador de eventos personalizado). Nota: El objeto LED debe ser una propiedad, no solo un campo en el objeto BlinkingLight para que funcione.

Entonces el controlador de eventos puede generar el evento enrutado personalizado de UserControl (FlashGreenEvent). A continuación se muestra el código de fondo que ahora complementa el código en el OP (he eliminado cualquier otro código irrelevante).

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

Otros consejos

En este caso, la mejor manera es usar WPF Command y crear un "BlinkTheLights" RoutedCommand: su BlinkingLightControl manejará el comando BlinkTheLights y responderá iniciando un StoryBoard que parpadea.

Si está haciendo un control personalizado, siempre puede establecer el activador fuera de la plantilla de control.

algo así como:

  <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>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top