Eigene Routed Events unter Silverlight

by Gregor Biswanger 19. November 2010 09:13

Routed Events sind gerade bei verschachtelten Steuerelementen enorm wichtig. Jedoch bringen Sie unter Silverlight einige Probleme mit sich. Zum einem sind Sie unter Silverlight auf folgende Events beschränkt:

KeyDown
KeyUp
GotFocus
LostFocus
MouseLeftButtonDown
MouseLeftButtonUp
MouseMove
MouseWheel
BindingValidationError
DragEnter
DragLeave
DragOver
Drop

Das wäre normal nicht wirklich schlimm, wenn man wie unter WPF seine eigenen Routed Events schreiben könnte. Leider kann man aktuell ab Silverlight 4 immer noch keine eigenen Routed Events schreiben. Das schränkt die Freiheiten bei bestimmten Anforderungen stark ein. Das nächste Problem wäre zudem die Abhängichkeit in der Code-Behind durch ein Event. Für die so eben genannten Probleme habe ich folgende Lösung parat: CallMethodAction-Behavior + UserControl-Facade.

Ein einfaches Beispiel: Die ListBox

Das folgende Beispiel verbildlicht ein gängiges Szenario unter Silverlight. Es soll auf ein Klick innerhalb der ListBox mit eigener Logik reagiert werden können. Dazu wurde bereits eine ListBox mit Beispieldaten und einem CallMethodAction-Behavior in Expression Blend 4 angelegt. Das CallMethodAction-Behavior soll auf das MouseLeftButtonDown-Event reagieren und die Methode ListBoxMouseLeftButtonDown im ViewModel aufrufen.

 

Das ist der folgende XAML-Code dazu:

   1:  ....
   2:          <ViewModel:ViewModelExample x:Key="ViewModel" />
   3:      </UserControl.Resources>
   4:   
   5:      <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource ViewModel}">
   6:          <ListBox x:Name="LbItems" Margin="36,43,39,58" ItemTemplate="{StaticResource ItemTemplate}" 
                        ItemsSource="{Binding Source={StaticResource SampleDataSource}, Path=Collection}">
   7:              <i:Interaction.Triggers>
   8:                  <i:EventTrigger EventName="MouseLeftButtonDown">
   9:                      <ei:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="ListBoxMouseLeftButtonDown" />
  10:                  </i:EventTrigger>
  11:              </i:Interaction.Triggers>
  12:          </ListBox>
  13:      </Grid>
  14:  ....

Listing.1 – XAML-Code mit ListBox und zugeordneten CallMethodAction-Behavior.

 

Das ViewModel hat zum Test folgenden Aufbau:

 

   1:  public class ViewModelExample
   2:  {
   3:     public void ListBoxMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
   4:     {
   5:         MessageBox.Show("Yeaahh... it´s work!");
   6:     }
   7:  }

Listing. 2 – Source-Code zum ViewModel.

Nun kann das folgende Beispiel auch gerne ohne MVVM-Pattern direkt mit Code-Behind-Code getestet werden. Egal welches der beiden Szenarios ausgeführt wird, man erhält das gleiche Ergebnis: Keine MessageBox! Außer man klickt ganz genau am Rand der ListBox. Es gebe jetzt zwar ein SelectionChanged-Event, das aber bei verschachtelten Items die innerhalb angeklickt werden ignoriert wird.

Woran kann das Problem liegen? Ein Bubbling-Event innerhalb der ListBox wird durch ein internes Grid-Element aufgefangen und gestoppt. Jetzt wäre es praktisch wenn man einen eigenen Routed Event dazu schreiben könnte.

Als Alternative gibt es folgende Lösung, man muss auf den allgemeinen Routed Event Manager implizit zugreifen und das bereits registrierte MouseLeftButtonDown-Event neu definieren. Dazu schreibt man sich einfach eine neue Klasse als Facade (Siehe Facade-Pattern). Die neue Klasse leitet von jeweiligen UserControl ab. Bei diesem Beispiel ist die ListBox dann die Basisklasse. Im Konstruktor greift man auf die abgeleitete Methode AddHandler zu. Diese bekommt dann das Event, die auszuführende Methode und eine Definition das der Handler weitergereicht werden darf. Die auszuführende Methode braucht auch nur auf dem Parameter der EventArgs zugreifen und gestattet dem Property Handler mittels false das es weitergereicht werden darf. Der Code dazu steht unter Listing 3.

 

   1:  public class ListBoxExtended : ListBox
   2:  {
   3:      public ListBoxExtended()
   4:      {
   5:          AddHandler(MouseLeftButtonDownEvent, new MouseButtonEventHandler(ListBox_MouseLeftButtonDown), true);
   6:      }
   7:   
   8:      private void ListBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
   9:      {
  10:          e.Handled = false;
  11:      }
  12:  }

Listing. 3 – Source-Code zur UserControl-Facade ListBoxExtended.

 

Die UserControl-Facade muss nur noch mittels XML-Namespace im XAML bekannt gemacht werden und die alte ListBox wird durch die neue ListBox ersetzt. Der restlichen Deklarationen bleiben hierbei unverändert.

 

   1:  ....
   2:         <ViewModel:ViewModelExample x:Key="ViewModel" />
   3:  </UserControl.Resources>
   4:   
   5:  <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource ViewModel}">
   6:      <SilverlightBubblingExample:ListBoxExtended x:Name="LbItems" Margin="36,43,39,58" ItemTemplate="{StaticResource ItemTemplate}" 
                                                       ItemsSource="{Binding Source={StaticResource SampleDataSource}, Path=Collection}">
   7:          <i:Interaction.Triggers>
   8:              <i:EventTrigger EventName="MouseLeftButtonDown">
   9:                  <ei:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="ListBoxMouseLeftButtonDown" />
  10:              </i:EventTrigger>
  11:          </i:Interaction.Triggers>
  12:      </SilverlightBubblingExample:ListBoxExtended>
  13:  </Grid>
  14:  ....

Listing. 4 – XAML-Code mit der neuen ListBoxExtended.

 

Nun wird bei jedem klick auf der ListBox das Event wie erwünscht gefeuert.

image

 

Source-Code Download

SilverlightBubblingExample.zip (262,87 kb)



Wenn ihnen der Artikel gefallen hat oder er für sie hilfreich war, bitten "kicken" sie ihn.
kick it on dotnet-kicks.de

Kommentare

Kommentar schreiben


(Zeigt dein Gravatar icon)  

  Country flag

biuquote
  • Kommentar
  • Live Vorschau
Loading



Powered by BlogEngine.NET 1.4.5.0
Theme by Extensive SEO

Über den Autor

Gregor Biswanger

Microsoft MVP für Client App Dev
XING

Gregor Biswanger (Microsoft MVP für Client App Dev) ist freier Consultant, Trainer, Autor und Speaker.


Seine Schwerpunkte liegen im Bereich der .NET-Architektur, agilen Prozessen und XAML. Er veröffentlichte vor kurzem seine DVD´s mit Video-Trainings zum Thema „Meine erste Windows 8 App“, „Windows Store Apps mit XAML und C#“ und „WPF 4.5 und Silverlight 5“ bei Addison-Wesley von video2brain.


Biswanger ist auch im Auftrag von Intel GmbH als Technologieberater für die Intel Developer Zone aktiv und ist Leader bei der Ingolstädter .NET Developers Group (INdotNET). 

 

Video über mich:
http://www.youtube.com/watch?v=mx_6SiiLxjk


Basta! 2011 Speaker

CLIPer

MCTS
Windows SharePoint Services 3.0 – Application Development (MCTS)