2017-03-02 2 views
1

Ich verwende eine externe Bibliothek mit einer Eigenschaft, die sich entsprechend bestimmter Ereignisse ändert. Manchmal ändert sich der Wert schnell (nur in Schritten zwischen 1 und 2). Ich möchte einen Event-Handler erstellen, der erkennt, ob der Wert geändert wird, und wenn er sich ändert, den Wert als Teil einer Gleichung abrufen, um ein Formular an einen Punkt auf dem Bildschirm zu verschieben. Ich bin derzeit einen Timer:Ereignishandler für eine Eigenschaftswertänderung einer externen Bibliothek erstellen

private var foo; 

public Form1() 
{ 
    this.InitializeComponent(); 

    this.foo = new Foo(); 
    this.DesktopLocation = new Point(foo.Property1 + 100, 500); 

    Timer timer = new Timer(); 
    timer.Interval = 1; 
    timer.Tick += new EventHandler(this.Timer_Tick); 
    timer.Start(); 
} 

private void Timer_Tick(object sender, EventArgs e) 
{ 
    this.DesktopLocation = new Point(this.foo.Property1 + 100, 500); 
} 

Was ich Trigger a custom event for an "external" value change basierte weg, aber ich hatte gehofft, für eine bessere Lösung, weil die Form hinter der vorgesehenen Stelle hinkt und flackert, wenn foo.Property1 mehrere Male in einer kurzen Zeitspanne ändert. Ich versuche, das Formular dem Punkt ähnlich zu folgen, wenn ein Benutzer das Formular mit der Maus bewegt. Vor dem Timer verwenden ich eine While-Schleife auf einem separaten Thread mit Rekursion:

 private void CheckFoo() 
     { 
      while (!this.Created) 
      { 
      } 

      if (new Point(this.foo.Property1 + 100, 500) != this.DesktopLocation) 
      { 
       this.Invoke(new Action(() => 
       { 
        this.DesktopLocation = new Point(this.foo.Property1 + 100, 500); 
       })); 
      } 

      while (this.DesktopLocation == new Point(this.foo.Property1 + 100, 500) && this.ContinueLoop) 
      { 
      } 

      if (this.ContinueLoop == false) 
      { 
       return; 
      } 
      else 
      { 
       this.CheckFoo(); 
      } 
     } 

Die obige Methode funktioniert visuell als etwa 30 Sekunden lang gedacht, aber dann stürzt es mit einem StackOverflowException an verschiedenen Stellen im Code, in der Regel bei this.DesktopLocation = new Point(this.foo.Property1 + 100, 500); aber manchmal anderswo (ich konnte den anderen Standort leider nicht replizieren). Ich lese über StackOverflowExceptions hier: https://www.dotnetperls.com/stackoverflowexception und es scheint, dass es ist, weil ich die Rekursionsschleife verwendete, also nehme ich an, dass ich die oben genannte Methode nicht verwenden kann. Gibt es einen Weg, dies ohne visuelle Probleme (oder Ausnahmen) zu erreichen?

+0

Dies bezieht sich auf Ihre 3rd-Party-Klasse, Vererbung, Umhüllung, Erstellen von Proxy darauf oder irgendetwas anderes – AlirezaJ

+0

@ AlirezaJ Ich verstehe nicht, bitte erarbeiten. Gab es eine Frage, die du verlinkt hast oder etwas? "Dies ist" schlägt eine Aussage vor, und das folgende 'bezogen auf 'schlägt vor, dass Sie beabsichtigten, eine Frage zu verbinden. – JordanZeotni

Antwort

0

Vor dem Timer ich eine While-Schleife auf einem separaten Thread mit Rekursion verwendet:

Warum? Warum Rekursion?

Es scheint mir Ihre Methode wie folgt geschrieben werden sollte:

private void CheckFoo() 
{ 
    // It would be better to just not start the thread that 
    // runs this method until the "Created" flag is set, rather 
    // that having this busy loop to wait. At the very least, there 
    // are better mechanisms for waiting than a loop like this. 
    while (!this.Created) 
    { 
    } 

    while (this.ContinueLoop) 
    { 
     if (new Point(this.foo.Property1 + 100, 500) != this.DesktopLocation) 
     { 
      this.Invoke(new Action(() => 
      { 
       this.DesktopLocation = new Point(this.foo.Property1 + 100, 500); 
      })); 
     } 
    } 
} 

Nun, diese Art der Abfrage ist nicht ideal. Zumindest sollten Sie einen dedizierten Thread erstellen und die Threadpriorität auf nicht höher als BelowNormal setzen und/oder einen Aufruf an Thread.Sleep(1) innerhalb der while-Schleifen einbeziehen (wodurch der Thread gezwungen wird, anderen beliebigen Threads nachzugeben). Aber wenn Sie wirklich müssen den DLL-Wert bei dieser Frequenz überwachen und die DLL selbst bietet keinen anderen Mechanismus als Polling für Sie über Änderungen an den Wert benachrichtigt werden, können Sie mit Code wie das stecken.

Denken Sie auch daran, dass der Anruf zu Invoke() teuer ist. Auch wenn sich der Wert mit den oben genannten Werten sehr stark ändert, sehen Sie die Updates möglicherweise immer noch nicht in der von Ihnen gewünschten Geschwindigkeit.

+0

Ich entfernte 'while (! This.Created) {}' vollständig, und die Anwendung lief gut, aber gäbe es eine bessere Möglichkeit, dies zu verhindern, um 'InvalidOperationException' zu verhindern, weil das Formular nicht vollständig geladen wurde? – JordanZeotni

+0

_ "aber würde es einen besseren Weg geben, damit umzugehen" _ - unmöglich zu sagen, ohne mehr Kontext. Aber wie ich oben in den Code-Kommentaren geschrieben habe, könntest du den Thread nicht starten, bis du weißt, dass er sicher ist. Z.B. Setzen Sie diesen Code in den Event-Handler für das Ereignis "Shown" Ihres Formulars. –

Verwandte Themen