Pytanie Jak wywołać zdarzenie po zmianie wartości zmiennej?


Obecnie tworzę aplikację w języku C # przy użyciu programu Visual Studio. Chcę utworzyć jakiś kod, aby gdy zmienna miała wartość 1, wykonywany jest pewien fragment kodu. Wiem, że mogę użyć instrukcji if, ale problem polega na tym, że wartość zostanie zmieniona w procesie asynchronicznym, więc technicznie instrukcja if może zostać zignorowana przed zmianą wartości.

Czy jest możliwe utworzenie procedury obsługi zdarzenia, aby po zmianie wartości zdarzenia wywołano zdarzenie? Jeśli tak, jak mogę to zrobić?

Jest całkowicie możliwe, że mogłem źle zrozumieć, jak działa instrukcja if! Każda pomoc byłaby bardzo cenna.


76
2018-04-30 14:21


pochodzenie


Dla jasności obserwowanie zmiany zmiennej jest możliwe tylko dla zmiennej, którą posiadasz (lub która jest już IObservable / INotifyPropertyChanged / Event-related). Nie można zaobserwować zmiany zmiennej systemowej, jeśli nie została zaprojektowana do obserwacji. - Cœur


Odpowiedzi:


Wydaje mi się, że chcesz stworzyć własność.

public int MyProperty
{
    get { return _myProperty; }
    set
    {
        _myProperty = value;
        if (_myProperty == 1)
        {
            // DO SOMETHING HERE
        }
    }
}

private int _myProperty;

Dzięki temu możesz uruchomić kod za każdym razem, gdy zmieni się wartość właściwości. Jeśli chcesz, możesz tu zorganizować wydarzenie.


95
2018-04-30 14:25





Za pomocą ustawiciela właściwości można podnieść zdarzenie za każdym razem, gdy zmieni się wartość pola.

Możesz mieć własnego delegata EventHandler lub możesz użyć słynnego delegata System.EventHandler.

Zwykle jest na to pewien wzór:

  1. Zdefiniuj wydarzenie publiczne z delegatem obsługi zdarzeń (który ma argument typu EventArgs).
  2. Zdefiniuj chronioną wirtualną metodę o nazwie OnXXXXX (na przykład OnMyPropertyValueChanged). W tej metodzie należy sprawdzić, czy deleger obsługi zdarzeń ma wartość null, a jeśli nie, można go nazwać (oznacza to, że do delegowania zdarzenia dołączona jest co najmniej jedna metoda).
  3. Zadzwoń do tej chronionej metody, gdy chcesz powiadomić subskrybentów, że coś się zmieniło.

Oto przykład

private int _age;

//#1
public event System.EventHandler AgeChanged;

//#2
protected virtual void OnAgeChanged()
{ 
     if (AgeChanged != null) AgeChanged(this,EventArgs.Empty); 
}

public int Age
{
    get
    {
         return _age;
    }

    set
    {
         //#3
         _age=value;
         OnAgeChanged();
    }
 }

Zaletą tego podejścia jest umożliwienie innym klasom, które chcą dziedziczyć po klasie, zmianę zachowania, jeśli jest to konieczne.

Jeśli chcesz uchwycić zdarzenie w innym wątku, który jest podnoszony, musisz uważać, aby nie zmienić stanu obiektów zdefiniowanych w innym wątku, co spowoduje zgłoszenie wyjątku krzyżowego. Aby tego uniknąć, możesz użyć metody Invoke na obiekcie, który chcesz zmienić, aby upewnić się, że zmiana zachodzi w tym samym wątku, w którym nastąpiło zdarzenie lub w przypadku, gdy masz do czynienia z formularzem systemu Windows może używać BackgourndWorker do robienia rzeczy w równoległym wątku ładnie i łatwo.


47
2018-04-30 15:00



Jedno z najlepszych wyjaśnień w całej sieci. Myślę, że w końcu rozumiem obsługę niestandardowych zdarzeń. Wdzięczny za ten post. - Ricardo Garcia


Platforma .NET faktycznie zapewnia interfejs, za pomocą którego można powiadomić subskrybentów o zmianie właściwości: System.ComponentModel.INotifyPropertyChanged. Ten interfejs ma jedno zdarzenie PropertyChanged. Jest zwykle używany w WPF do wiązania, ale znalazłem go przydatny w warstwach biznesowych jako sposób standaryzacji powiadomień o zmianie właściwości.

Jeśli chodzi o bezpieczeństwo wątku, umieściłbym blokadę w seterze, abyś nie wpadł na żadne warunki wyścigowe.

Oto moje przemyślenia w kodzie :):

public class MyClass : INotifyPropertyChanged
{
    private object _lock;

    public int MyProperty
    {
        get
        {
            return _myProperty;
        }
        set
        {
            lock(_lock)
            {
                //The property changed event will get fired whenever
                //the value changes. The subscriber will do work if the value is
                //1. This way you can keep your business logic outside of the setter
                if(value != _myProperty)
                {
                    _myProperty = value;
                    NotifyPropertyChanged("MyProperty");
                }
            }
        }
    }

    private NotifyPropertyChanged(string propertyName)
    {
        //Raise PropertyChanged event
    }
    public event PropertyChangedEventHandler PropertyChanged;
}


public class MySubscriber
{
    private MyClass _myClass;        

    void PropertyChangedInMyClass(object sender, PropertyChangedEventArgs e)
    {
        switch(e.PropertyName)
        {
            case "MyProperty":
                DoWorkOnMyProperty(_myClass.MyProperty);
                break;
        }
    }

    void DoWorkOnMyProperty(int newValue)
    {
        if(newValue == 1)
        {
             //DO WORK HERE
        }
    }
}

Mam nadzieję, że to jest pomocne :)


35
2018-04-30 21:13



+1 za włączenie blokady, której nie uwzględniają inne odpowiedzi. - ctacke
Jaki jest pożytek z obiektu _lock? - Lode Vlaeminck
@LodeVlaeminck zapobiega zmianie wartości właściwości podczas przetwarzania zdarzenia. - David Suarez


po prostu użyj nieruchomości

int  _theVariable;
public int TheVariable{
  get{return _theVariable;}
  set{
    _theVariable = value; 
    if ( _theVariable == 1){
      //Do stuff here.
    }
  }
}

8
2018-04-30 14:28