2016-05-17 20 views
1

Nehmen wir an, ich habe eine einfache Form in C# (winforms) mit zwei Textfeldern, einem Schieberegler und einem Objekt namens "the_volume". Ein Ereignis (OnPropertyChanged) wird gesendet, wenn sich "the_volume.value" ändert. Wie kann ich CLEAN die vier Objekte synchronisieren, ohne eine Endlosschleife zu verursachen?Unendliche Schleife von Ereignissen

  • Ohne die Ereignis-Listener zu trennen
  • Ohne eine boolean Verwendung zu "guard"
  • Ohne Datenbindung mit

kleines Beispiel: Slider Änderungen -> Form :: slider_changed -> the_volume ist gesetzt -> form :: the_volume_changed -> setze den slider und die texboxes werte -> endless loop ...

Mein erster Instinkt wäre es, das Senden eines Ereignisses zu vermeiden, wenn der Wert nicht cha ist nges aber,

1- Wie kann ich wissen, ob die .net Kontrollen dasselbe tun werden? (Dh Auslösung nicht, wenn der Wert das gleiche ist)

2- Was für Fehler bin ich, dass es wäre ein „nutzloser“ Setter Anruf mit dieser Lösung (Set -> geändert -> set -> Stoppschleife)

+2

afaik 'TextBox' und' Slider' führen keine Änderungsereignisse auf, wenn keine _real_Änderung vorhanden war (wenn der _new_ Wert der gleiche wie der _old_Einzelwert ist). Also sollte es keine Endlosschleife geben. –

+0

aber ist der extra "setter" Anruf vermeidbar? – d08z

+0

glaube nicht, dass es ein Leistungsproblem ist, also brauchen Sie es nicht zu vermeiden. Wenn du es wirklich vermeiden willst, würde ich den booleschen "Wächter" vorschlagen. –

Antwort

0

Ich weiß, dies ist eine WinForms Frage, aber die Art, wie WPF tut, sollte Ihnen helfen. Sie können INotifyPropertyChanged Beispiele für weitere Einzelheiten, die Forschung aber ist hier die Grundlagen:

//have a backing variable 
private double _volume = 0; 

//have a property 
public double Volume 
{ 
    get { return _volume; } 
    set 
    { 
     // prevent any event firing if nothing changed 
     if(_volume == value) 
     { 
      return; 
     } 

     // now we can set 
     _volume = value; 

     // something really changed, fire some event 
     this.NotifyPropertyChanged(); 
    } 
} 

Jetzt sind alle Ihre Zuhörer wird nur benachrichtigt, wenn etwas wirklich geändert hat. Diese Art der Überprüfung dann Feuer kann auf fast jedes Beobachter Muster Problem angewendet werden, die Sie haben. Dies verhindert ein Ereignis-Looping, wie Sie es in Ihrer Frage angegeben haben.

+0

Ja, das ist eine sehr gute Lösung, aber was mich ein wenig nervt, ist der extra Setter Call – d08z

+0

Es ist ein if-Check und nichts wird gesetzt, es sei denn es muss. Sie haben in vielen Ihrer Kommentare einen "Extra Setter Call" erwähnt. Vielleicht verstehe ich falsch, was du damit meinst. Der Overhead von Feuerungsereignissen ist viel teurer als ein If-Check oder einen Wert zu setzen. Denken Sie daran, Speicher wurde bereits zugewiesen, um Ihre Variable zu speichern, so dass der Wert so gering wie möglich ist. Die Sache, die Sie vermeiden wollen, ist ein Neuzeichnen der Benutzeroberfläche, so dass das Ereignis am besten ist, wenn Leistung ein Problem darstellt. – ManOVision

+0

Textbox1 Setter -> Event geändert -> Textbox2 Setter -> geändert -> Textbox1 Setter -> - Ende der Schleife-- Aber Sie haben Recht, es ist wirklich nichts Performance-weise – d08z

0

Ich hätte ein einzelnes Objekt, das für das Routing der Ereignisse verantwortlich ist. Nennen wir es VolumeChangedEventRouter. Es würde sein eigenes Ereignis "Volumenänderung" haben, an das andere Entitäten teilnehmen könnten.

VolumeChangedEventRouter würde jedes Ihrer Steuerelemente abonnieren (oder abonniert werden), die das Ereignis "Volume geändert" auslösen könnten.

Dann würde jedes Ihrer Steuerelemente das Ereignis "Volume geändert" von VolumeChangedEventRouter abonnieren (oder abonnieren).

Dann würde die VolumeChangedEventRouter das aktuelle Volumen kennen, und somit würde es wissen, ob es sich geändert hat und daher, ob das Ereignis an seine Abonnenten weitergegeben werden soll.

Sie würden wahrscheinlich die Abhängigkeitsinjektion verwenden, um die VolumeChangedEventRouter an jede der Klassen zu übergeben, die das Ereignis "Volume geändert" abonnieren müssen. (Sie könnten sogar VolumeChangedEventRouter gestalten wollen, so dass sie eine Schnittstelle implementiert, die nur enthält das Ereignis „Volumen verändert“, und übergeben Sie, dass zu den Kontrollen Abhängigkeiten zu minimieren.)

Es könnte sogar möglich sein, eine gemeinsame IVolumeChanger Schnittstelle zu haben was durch VolumeChangedEventRouter AND alle Steuerelemente implementiert wird, da sie alle "volume changed" Ereignisse auslösen werden. Das würde die Kopplung ziemlich reduzieren.

+0

Wie kann ein TextBox-Steuerelement einem Ereignis zugeordnet werden? – d08z

+0

@ d08z Sie benötigen einen Controller für die TextBox - normalerweise das Benutzersteuerelement, das sie enthält (für einfache Fälle) oder eine separate Controller-Klasse (für komplexere Fälle). Der Controller würde das Ereignis abonnieren und es entsprechend behandeln. –

+0

Ja, aber es würde immer noch zusätzliche nutzlose Setter-Aufrufe geben. Aber ich denke nicht, dass es auf die Leistung ankommt. – d08z

Verwandte Themen