Mausklick in Win.Forms per Reactive Extensions abfragen

Die Reactive Extensions von Microsoft können schon ein cooles Werkzeug sein. Wer sich schon einmal damit beschäftigt hat, weiß, dass dieses Framework vom Funktionsumfang her eine sehr gute Ergänzung ist, von der Syntax her aber sehr ungewohnt.

Ein gutes Beispiel dafür habe ich neulich bei einem relativ einfachen Thema gemacht: Einen einfachen Mausklick in einem Windows.Forms Panel abfangen. Das Standard-Ereignis konnte ich nicht nehmen, da dieses auch dann feuert, wenn die Maustaste länger unten gehalten wurde. In diesem Fall möchte ich das Ereignis aber nicht, da länger gedrückte Maustaste in diesem Fall eine andere Bedeutung hat.

Was würde man also normalerweise ohne Reactive Extensions in diesem Fall machen? Die Ereignisse MouseDown und MouseUp separat abonnieren, in ersteren einen Zeitstempel merken, gegen den man dann in letzteren prüfen kann, ob wirklich ein Klick stattgefunden hat. Nachteilig: Die Logik für diese Abfrage ist damit etwas verzweigt. Man bekommt zwei Event-Handler und einen zusätzlichen Member, was die Klasse nur unnötig komplexer macht. Man will ja schließlich nur einen Klick abfragen!

Ich habe mich also kurz hingesetzt und versucht, eben dieses Thema per Reactive Extensions zu lösen. Herausgekommen ist folgender Code.

// Observe mouse click event
var mouseDownEvent = Observable.FromEventPattern<MouseEventArgs>(m_ctrlCanvas3D, "MouseDown");
var mouseUpEvent = Observable.FromEventPattern<MouseEventArgs>(m_ctrlCanvas3D, "MouseUp");
var mouseClick = from down in mouseDownEvent
    where down.EventArgs.Button == MouseButtons.Left
    let timeStampDown = DateTime.UtcNow
    from up in mouseUpEvent
    where up.EventArgs.Button == MouseButtons.Left
    let timeStampUp = DateTime.UtcNow
    where timeStampUp - timeStampDown < TimeSpan.FromMilliseconds(200.0)
    select new { Down = down, Up = up };
mouseClick.Subscribe((givenItem) =>
{
    ...
});

Sieht nach etwas viel Code für ein kleines Problem aus, lässt sich aber erstaunlich gut lesen und verstehen, wenn man den Code von oben nach unten durchgeht. Vorteil an dieser Variante ist, dass die Erkennungslogik für den Mausklick an einer Stelle steht. Weiterhin hat man nur ein Ereignis, welches man registrieren muss (das Subscribe).

Quellen:

3 Gedanken zu „Mausklick in Win.Forms per Reactive Extensions abfragen“

  1. Hallo Roland
    (ich schreibe so, weil Sehr geehrter Herr K. nicht richtig passend ist – ich hoffe, Sie akzeptieren das)

    ich bin ein Hobby Programierer und ich habe mich der Digitalisierung von alten Schmalfilmen (Super 8, Single 8, Normal 8, Pathé 9,5 mm und 16 mm) verschrieben. Näheres über mich und meine Projekte finden Sie unter meiner Webseite, die ich unten angegeben habe.
    Ich erstelle meine Projekte mit Visual Studio Community 2019 und für mein neuestes Projekt „CineFrameCatcher“ verwende ich Accord .NET. Ich habe dabei aber Probleme mit verschiedenen Digital Microskopen, die ich als VideoCaptureDevice verwenden möchte. Ich habe z.b. mit dem Bresser National Geographic schon mehrfach Bluescreens erlebt, die mit dem alten Treiber aus Windows NT Zeiten zusammenzuhängen scheinen – Modul Name AVEOdcnt). Mit dem Celestron Mikroskop Pro funktioniert es einigermassen, aber manchmal erfasst es einfach keine Bilder und gibt „Null“-Objekte zurück.
    Meine Überlegung ist es nun, auf Windows Media Foundation umzusteigen. Bräuchte da aber einen Wrapper für C#. Ist das ratsem, denn C++ will ich in meinem Alter nicht mehr erlernen.
    Können Sie da etwas empfehlen. Ist etwa Ihr Code aus dem „einfachen Media Player“ verwendbar oder gibt es etwas geeigneteres. Und ist es erlaubt, diesen Code zu verwenden.
    Ich wäre Ihnen dankbar, wenn Sie mir da etwas unter die Arme greifen könnten.

    Mit freundlichen Grüßen
    Wolfgang Kurz

    Antworten
  2. Hallo Wolfgang,
    den Code hier auf der Seite kannst du natürlich frei verwenden – kein Problem. Bei den Sachen mit Media Foundation habe ich immer SharpDX als Wrapper verwendet. Das hat so recht gut funktioniert, der Wrapper ist aber nicht in einer so hohen Qualität wie für zum Beispiel Direct3D. Stell dich also auf ein paar Stolpersteine ein.
    Ansonsten wird SharpDX auch schon länger nicht mehr weiterentwickelt (siehe https://github.com/sharpdx/SharpDX).

    Seit meinen Posts hier habe ich mich auch nicht mehr so tief mit den Video-Themen beschäftigt. Wenn ich heute damit anfangen würde, würde ich mich aber mit ffmpeg beschäftigen (https://ffmpeg.org/). Ob es dazu einen guten C#-Wrapper gibt, weiß ich aber leider nicht.

    Hoffe, das hilft weiter.

    Viele Grüße
    Roland

    Antworten
  3. Hallo Roland,

    vielen Dank für deine Antwort.
    Es hat zwar etwas gedauert, bis ich reagieren konnte. Ich hatte einige happige Probleme zu lösen. Die sind aber jetzt alle im Griff.
    Jetzt kann ich mich mit der entweder FFMPEG oder der Media Foundation beschäftigen.
    Ich werde mit auch mal SharpDX zu gemüte führen.

    Der CineFrameCatcher läuft jetzt zufriedenstellend. Siehe meine Webseite: http://www.uwkurz.de/home

    Antworten

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.