Hallo, ich experimentiere gerade etwas mit dem PropertyChanged Interface und habe dazu eine Frage.
Ich möchte mein Klassen-Objekt aktuell halten. Wenn sich eine Property des Objektes ändert, dann möchte ich das
das UI aktualisieren.
Nur als Beispiel: Ich erstelle eine Rechnung. Das Klassen-Objekt Rechnung hat die Property Betrag und Umsatzsteuer.
Wenn der Benutzer einen Bruttobetrag eingibt, dann soll er die berechnete Umsatzsteuer unmittelbar sehen.
Ich habe da was zusammengebastelt, das Event wird aber nach unnötigerweise (in diesem Beispiel) doppelt abgefeuert.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82:
| public class ClassRechnung : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private readonly Dictionary<string, object> propertyValues;
public ClassRechnung() { propertyValues = new Dictionary<string, object>(); } public int Betrag { get { return Get(() => Betrag); } set { if (value != Betrag) { Set(() => Betrag, value); } } }
public decimal MwST { get { return Get(() => MwST); } set { if (value != MwST) { Set(() => MwST, value); } } }
protected void Set<T>(Expression<Func<T>> expression, T value) { string propertyName = GetPropertyNameFromExpression(expression); Set(propertyName, value); } public static string GetPropertyNameFromExpression<T>(Expression<Func<T>> expression) { MemberExpression memberExpression = (MemberExpression)expression.Body; return memberExpression.Member.Name; }
protected void Set<T>(string name, T value) { if (propertyValues.ContainsKey(name)) { propertyValues[name] = value; OnPropertyChanged(name); } else { propertyValues.Add(name, value); OnPropertyChanged(name); } } protected T Get<T>(string name) { if (propertyValues.ContainsKey(name)) { return (T)propertyValues[name]; } return default(T); } protected T Get<T>(Expression<Func<T>> expression) { string propertyName = GetPropertyNameFromExpression(expression); return Get<T>(propertyName); }
protected void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } } |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:
| public partial class Form1 : Form { ClassRechnung _Rechnung = null; public Form1() { InitializeComponent(); _Rechnung = new ClassRechnung(); _Rechnung.PropertyChanged += ClassRechnung_PropertyChanged; } private void ClassRechnung_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { UpdateUI(); }
private void textBoxBetrag_TextChanged(object sender, System.EventArgs e) { int Betrag = 0; if (int.TryParse(textBoxBetrag.Text, out Betrag)) { _Rechnung.Betrag = Betrag; _Rechnung.MwST = (Betrag * 0.19M); } }
private void UpdateUI() { labelBetrag.Text = _Rechnung.Betrag.ToString(); labelMwst.Text = _Rechnung.MwST.ToString(); }
} |
Ist vllt ein schlechtes Beispiel, weil die MwSt normalerweise nicht vom Benutzer verändert wird und ich somit das Event bei
dieser Property nicht abfeuern muss. Wenn es aber verschiedene Rechnungspositionen gibt, wo der Benutzer die Beträge ändern kann, dann möchte ich mein Rechnungsobjekt aktuell halten,
ohne das das Event mehrfach abgefeuert wird.
Ich könnte pfuschen und den handler, nach dem der Betrag gesetzt wurde rausnehmen und dann wieder zuweisen, so:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| _Rechnung .Betrag = Betrag;
_Rechnung .PropertyChanged -= ClassRechnung _PropertyChanged;
_Rechnung .MwST = (Betrag * 0.19M); _Rechnung .xxx = xxx; _Rechnung .xxx = xxx; _Rechnung .xxx = xxx; _Rechnung .xxx = xxx;
_Rechnung .PropertyChanged += ClassRechnung _PropertyChanged; |
Wie kann ich es besser lösen?