Rx – Lösung zur ersten Webcast-Übung

by Gregor Biswanger 2. August 2011 04:59

imageBeim Webcast “Einstieg in die Programmierung asynchroner und event-basierter Anwendungen”, stellte ich zwei Übungen zum Einstieg in Rx (Reactive Extensions) bereit.

Die erste Übung beschäftige sich hauptsächlich mit Rx unter Silverlight. Hier sollte eine Doppelklick-Logik für einen Button implementiert werden. Einmal auf den “normalen” Lösungsweg und zum zweiten mit Hilfe von den Reactive Extensions.

Zur ersten Aufgabe hatte ich bereits dem dot.net-Magazin eine Lösung bei der Kolumne “Silverlight Expertise” veröffentlicht gehabt, das auch schon Online frei ersichtlich ist: “Silverlight: Doppelt klicken, einfach laden”.

 

 

 

Silverlight - Klassische Doppelklick-Logik

 

   1:  namespace SilverlightApplication
   2:  {
   3:    public partial class MainPage : UserControl
   4:    {
   5:      private DispatcherTimer _doubleClickTimer;
   6:   
   7:      public MainPage()
   8:      {
   9:          InitializeComponent();
  10:   
  11:          _doubleClickTimer = new DispatcherTimer();
  12:          _doubleClickTimer.Interval = new TimeSpan(0, 0, 0, 0, 200);
  13:          _doubleClickTimer.Tick += DoubleClickTimerTick;
  14:      }
  15:   
  16:      private void DoubleClickTimerTick(object sender, EventArgs e)
  17:      {
  18:        _doubleClickTimer.Stop();
  19:      }
  20:   
  21:      private void BnTest_Click(object sender, RoutedEventArgs e)
  22:      {
  23:        if(_doubleClickTimer.IsEnabled)
  24:        {
  25:          MessageBox.Show("Doppelklick ausgeführt!");
  26:        }
  27:        else
  28:        {
  29:          _doubleClickTimer.Start();
  30:        }
  31:      }
  32:    }
  33:  }

 

Sehr unschön an dieser Lösung ist, das bei der auszuführenden Methode, auch noch Logik zum Doppelklick implementiert seien muss.

 

Silverlight - Doppelklick-Logik mittels Rx

Als nächste Aufgabe wurde ein Lösungsweg mittels Rx erwartet. Dazu habe ich zwei Projekte aus den Einsendungen ausgewählt. Die erste Lösung erhielt ich von Alexander Partsch aus Wien. Er baute dazu ein eigenes Control, das zusätzlich ein Command zur Verfügung stellte, das erst bei einem Doppelklick gefeuert wird. Ehrlich gesagt, war das schon zu viel und umfangreich für diese Übung. Eine einfache Implementierung bei der Vorlage hätte ausgereicht. Dennoch soll diese Mühe belohnt werden. Ich bin absolut begeistert von der Implementierung und möchte diese nicht vorenthalten. Hier ist der Source-Code des eigenen Controls:

 

   1:  using System;
   2:  using System.Windows;
   3:  using System.Windows.Controls;
   4:  using System.Windows.Input;
   5:  using System.Reactive.Linq;
   6:   
   7:  namespace DotnetBlog_RXAndSilverlight.CustomControls
   8:  {
   9:      public class DoubleClickButton : Button
  10:      {
  11:          public static readonly DependencyProperty DoubleClickCommandProperty = 
  12:              DependencyProperty.Register("DoubleClickCommand", typeof(ICommand), typeof(DoubleClickButton), null);
  13:   
  14:          public ICommand DoubleClickCommand
  15:          {
  16:              get { return (ICommand)GetValue(DoubleClickCommandProperty); }
  17:              set { SetValue(DoubleClickCommandProperty, value); }
  18:          }
  19:   
  20:          public DoubleClickButton()
  21:          {
  22:              Observable.FromEventPattern<RoutedEventArgs>(this, "Click")
  23:                  .TimeInterval()
  24:                  .Where(next => next.Interval.TotalMilliseconds <= 200)
  25:                  .Subscribe(next => DoubleClickCommand.Execute(CommandParameter)); 
  26:          }
  27:      }
  28:  }

Listing 2.1 - Silverlight – Rx Doppelklick-Logik von Alexander Partsch aus Wien.

 

Im XAML kann dann das Control folgendermaßen mit einem Command-Property gebunden werden:

<myConstrols:DoubleClickButton x:Name="doubleClickButton" Content="Click me" DoubleClickCommand="{Binding ButtonClick}" />

 

Reactive Extensions - TimeInterval

Hier möchte ich auf die Extension-Method “TimeInterval” von Rx eingehen. Diese beinhaltet eine Art Zeitstempel. Worin jeweils vom letzten Aufruf des Datenstroms die Zeit gemessen wird. Beim ersten klick auf den Button, wird der Zeitstempel aktiv. Beim zweiten klick, wird dann der Zeitstempel zurückgesetzt und deren Dateninformation weitergereicht. Bei der Where-Methode kann dann der Zeitabstand des zweiten klicks verglichen werden. Sollte dieser unter 200 Millisekunden liegen, wird es als Doppelklick akzeptiert.

image

 

Die zweite Einreichung kam vom Dennis Bischof aus Göppingen (und Leiter der .NET Developer Group Göppingen), er sendete mir erst eine Lösung mit der Extension-Method Buffer und anschließend eine Korrektur mit TimeInterval. Allerdings kann Buffer gleichermaßen dafür verwendet werden, das ich Euch nicht vorenthalten möchte:

   1:  namespace SilverlightRxDoubleClick
   2:  {
   3:      public partial class MainPage : UserControl
   4:      {
   5:          public MainPage()
   6:          {
   7:              InitializeComponent();
   8:   
   9:              // Hinweis! Verwende FromEventPattern und Buffer.
  10:              Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(o => BnClickMe.Click += o, o => BnClickMe.Click -= o)
  11:                  .Buffer(TimeSpan.FromMilliseconds(800))
  12:                  .Where(bufferResult => bufferResult.Count == 2)
  13:                  .ObserveOnDispatcher()
  14:                  .Subscribe(x => ButtonClick());
  15:          }
  16:   
  17:          public void ButtonClick()
  18:          {
  19:              // TODO: Erst bei einem Doppelklick, darf dieser Code ausgeführt werden.
  20:              MessageBox.Show("Doppelklick ausgeführt!");
  21:          }
  22:      }
  23:  }

Listing 2.2 - Silverlight – Rx Doppelklick-Logik von Dennis Bischof aus Göppingen.

 

Reactive Extensions – Buffer

Buffer sammelt die Werte von der Observable sequence für einen bestimmten Zeitraum. Gegen Ende werden alle Daten gesammelt geliefert. Bei Dennis seiner Lösung, gibt er dem Buffer eine Regel mittels TimeSpan mit. Er möchte nur alle Datenpakete erhalten, die sich nach 800 Millisekunden gesammelt hatten. Danach wird überprüft ob es auch nur 2 Pakete waren. Wenn ja, wird es als Doppelklick akzeptiert.

image

Fazit

Zum Vergleich der klassischen Lösung, wird viel weniger Code mittels Rx benötigt. Zudem können besser Regeln via Linq gesetzt werden, ab wann man wirklich einen Aufruf erhalten möchte. Die auszuführende Methode, bleibt frei von der Doppelklick-Logik.

Eine weitere Übung unter WPF steht noch offen, gerne können weiterhin eure Lösungen eingereicht werden, die ich mit dem nächsten Post veröffentlichen werde.

Vielen Dank für die Lösungen an Alexander Partsch und Dennis Bischof. Respekt!



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)