WPF - Eventos enrutados

UN routed eventes un tipo de evento que puede invocar controladores en múltiples oyentes en un árbol de elementos en lugar de solo el objeto que generó el evento. Básicamente es un evento CLR que es compatible con una instancia de la clase Evento enrutado. Está registrado con el sistema de eventos de WPF. RoutedEvents tiene tres estrategias de enrutamiento principales que son las siguientes:

  • Evento directo
  • Evento burbujeante
  • Evento de túnel

Evento directo

Un evento directo es similar a los eventos en formularios de Windows que son provocados por el elemento en el que se origina el evento.

A diferencia de un evento CLR estándar, los eventos enrutados directos admiten el manejo de clases y se pueden usar en Event Setters y Event Triggers dentro de su estilo de su Control personalizado.

Un buen ejemplo de un evento directo sería el evento MouseEnter.

Evento burbujeante

Un evento burbujeante comienza con el elemento donde se origina el evento. Luego viaja por el árbol visual hasta el elemento superior del árbol visual. Entonces, en WPF, lo más probable es que el elemento superior sea una ventana.

Evento de túnel

Los controladores de eventos en la raíz del árbol de elementos se invocan y luego el evento viaja por el árbol visual a todos los nodos secundarios hasta que alcanza el elemento en el que se originó el evento.

La diferencia entre un evento de burbujeo y un túnel es que un evento de túnel siempre comenzará con una vista previa.

En una aplicación WPF, los eventos a menudo se implementan como un par de túnel / burbujeo. Por lo tanto, tendrá una vista previa de MouseDown y luego un evento MouseDown.

A continuación se muestra un ejemplo simple de un evento enrutado en el que se crean un botón y tres bloques de texto con algunas propiedades y eventos.

<Window x:Class = "WPFRoutedEvents.MainWindow" 
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   Title = "MainWindow" Height = "450" Width = "604" ButtonBase.Click  = "Window_Click" >
	
   <Grid> 
      <StackPanel Margin = "20" ButtonBase.Click = "StackPanel_Click">
		
         <StackPanel Margin = "10"> 
            <TextBlock Name = "txt1" FontSize = "18" Margin = "5" Text = "This is a TextBlock 1" /> 
            <TextBlock Name = "txt2" FontSize = "18" Margin = "5" Text = "This is a TextBlock 2" /> 
            <TextBlock Name = "txt3" FontSize = "18" Margin = "5" Text = "This is a TextBlock 3" /> 
         </StackPanel> 
			
         <Button Margin = "10" Content = "Click me" Click = "Button_Click" Width = "80"/> 
      </StackPanel> 
   </Grid> 
	
</Window>

Aquí está el código C # para la implementación de eventos Click para Button, StackPanel y Window.

using System.Windows; 
 
namespace WPFRoutedEvents { 
   /// <summary> 
      /// Interaction logic for MainWindow.xaml 
   /// </summary>
	
   public partial class MainWindow : Window { 
	
      public MainWindow() { 
         InitializeComponent(); 
      }  
		
      private void Button_Click(object sender, RoutedEventArgs e) { 
         txt1.Text = "Button is Clicked"; 
      } 
		
      private void StackPanel_Click(object sender, RoutedEventArgs e) { 
         txt2.Text = "Click event is bubbled to Stack Panel"; 
      } 
		
      private void Window_Click(object sender, RoutedEventArgs e) { 
         txt3.Text = "Click event is bubbled to Window"; 
      }
		
   } 
}

Cuando compile y ejecute el código anterior, producirá la siguiente ventana:

Al hacer clic en el botón, los bloques de texto se actualizarán, como se muestra a continuación.

Si desea detener el evento enrutado en cualquier nivel en particular, deberá configurar e.Handled = true;

Cambiemos el StackPanel_Click evento como se muestra a continuación -

private void StackPanel_Click(object sender, RoutedEventArgs e) { 
   txt2.Text = "Click event is bubbled to Stack Panel"; 
   e.Handled = true; 
}

Al hacer clic en el botón, se dará cuenta que el evento click no se dirigirá a la ventana y se detendrá en el StackPanel y el 3 rd no se actualizará bloque de texto.

Eventos enrutados personalizados

En .NET Framework, también se pueden definir eventos enrutados personalizados. Debe seguir los pasos que se indican a continuación para definir un evento enrutado personalizado en C #.

  • Declare y registre su evento enrutado con la llamada al sistema RegisterRoutedEvent.

  • Especifique la estrategia de enrutamiento, es decir, burbuja, túnel o directo.

  • Proporcione el controlador de eventos.

Tomemos un ejemplo para comprender mejor los eventos enrutados personalizados. Siga los pasos que se indican a continuación:

  • Cree un nuevo proyecto de WPF con WPFCustomRoutedEvent

  • Haga clic derecho en su solución y seleccione Agregar> Nuevo elemento ...

  • Se abrirá el siguiente cuadro de diálogo, ahora seleccione Custom Control (WPF) y nombrarlo MyCustomControl.

  • Haga clic en el Add y verá que se agregarán dos archivos nuevos (Themes / Generic.xaml y MyCustomControl.cs) en su solución.

El siguiente código XAML establece el estilo del control personalizado en el archivo Generic.xaml.

<ResourceDictionary 
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:local = "clr-namespace:WPFCustomRoutedEvent">
	
   <Style TargetType = "{x:Type local:MyCustomControl}"> 
      <Setter Property = "Margin" Value = "50"/> 
      <Setter Property = "Template"> 
         <Setter.Value> 
            <ControlTemplate TargetType = "{x:Type local:MyCustomControl}">
				
               <Border Background = "{TemplateBinding Background}" 
                  BorderBrush = "{TemplateBinding BorderBrush}" 
                  BorderThickness = "{TemplateBinding BorderThickness}"> 
                  <Button x:Name = "PART_Button" Content = "Click Me" /> 
               </Border> 
					
            </ControlTemplate> 
         </Setter.Value> 
      </Setter> 
   </Style> 
	
</ResourceDictionary>

A continuación se muestra el código C # para el MyCustomControl class que hereda del Control class en el que se crea un evento enrutado personalizado Click para el control personalizado.

using System.Windows; 
using System.Windows.Controls;  

namespace WPFCustomRoutedEvent { 

   public class MyCustomControl : Control { 
	
      static MyCustomControl() { 
         DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), 
            new FrameworkPropertyMetadata(typeof(MyCustomControl))); 
      } 
		
      public override void OnApplyTemplate() { 
         base.OnApplyTemplate();
			
         //demo purpose only, check for previous instances and remove the handler first 
         var button  =  GetTemplateChild("PART_Button") as Button; 
         if (button ! =  null) 
         button.Click + =  Button_Click;  
      } 
		
      void Button_Click(object sender, RoutedEventArgs e) { 
         RaiseClickEvent(); 
      } 
		
      public static readonly RoutedEvent ClickEvent  =  
         EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, 
         typeof(RoutedEventHandler), typeof(MyCustomControl)); 
			
      public event RoutedEventHandler Click { 
         add { AddHandler(ClickEvent, value); } 
         remove { RemoveHandler(ClickEvent, value); } 
      } 
		
      protected virtual void RaiseClickEvent() { 
         RoutedEventArgs args = new RoutedEventArgs(MyCustomControl.ClickEvent); 
         RaiseEvent(args); 
      }
		
   } 
}

Aquí está la implementación del evento enrutado personalizado en C # que mostrará un cuadro de mensaje cuando el usuario haga clic en él.

using System.Windows;  

namespace WPFCustomRoutedEvent { 
   // <summary> 
      // Interaction logic for MainWindow.xaml
   // </summary> 
	
   public partial class MainWindow : Window { 
	
      public MainWindow() { 
         InitializeComponent(); 
      }  
		
      private void MyCustomControl_Click(object sender, RoutedEventArgs e) { 
         MessageBox.Show("It is the custom routed event of your custom control"); 
      } 
		
   } 
}

Aquí está la implementación en MainWindow.xaml para agregar el control personalizado con un evento enrutado Click.

<Window x:Class = "WPFCustomRoutedEvent.MainWindow" 
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:local = "clr-namespace:WPFCustomRoutedEvent"
   Title = "MainWindow" Height = "350" Width = "604"> 
	
   <Grid> 
      <local:MyCustomControl Click = "MyCustomControl_Click" /> 
   </Grid> 
	
</Window>

Cuando se compila y ejecuta el código anterior, producirá la siguiente ventana que contiene un control personalizado.

Al hacer clic en el control personalizado, producirá el siguiente mensaje.