Databinding Winforms Objekt-Property an Textbox

  • C#
  • .NET 5–6

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Databinding Winforms Objekt-Property an Textbox

    Hi,
    bei folgendem Code dachte ich, dass bei Btn-Press der Text von Textbox1 (TxbxEnter) nach Textbox2 (TxbxName) 'kopiert'/angezeigt würde. Textbox2 bleibt aber leer.
    Wie schaffe ich es, dass immer der aktuelle Wert vom Property 'Name' der Klasse MyModel in der Textbox angezeigt wird.
    (2x Txbx 1xbutton)

    Frm:

    C#-Quellcode

    1. namespace WF_SimpleDatabindingTxbx
    2. {
    3. public partial class Form1 : Form
    4. {
    5. public MyModel MyObjM = new();
    6. public Form1()
    7. {
    8. InitializeComponent();
    9. TxbxName.DataBindings.Add(new Binding("Text", MyObjM, nameof(MyModel.Name), false, DataSourceUpdateMode.OnPropertyChanged));
    10. }
    11. private void BtnEnter_Click(object sender, EventArgs e)
    12. {
    13. MyObjM.Name = TxbxEnter.Text;
    14. }
    15. }
    16. }


    Model:

    C#-Quellcode

    1. namespace WF_SimpleDatabindingTxbx
    2. {
    3. public class MyModel
    4. {
    5. public string Name { get; set; } = "";
    6. }
    7. }
    codewars.com Rank: 4 kyu
    Ich hab meine Model-Klasse um INotifyPropertyChange erweitert. So läuft es tatsächlich.
    Ich ging davon aus das DataSourceUpdateMode.OnPropertyChanged die Propertys automatisch überwacht und ich nicht dafür sorgen muss, dass PropertyChanged ausgelöst wird.

    Aber geht es wirklich nicht ohne das ganze Brimborium?
    Mich nervt das Aussehen meiner Models mit den ganzen private-Backingfields.

    Gibt es nicht so was wie UpdateAllBindingsFromForm(); oder wenigstens ​TxbxName.Update.BindingSource();?

    C#-Quellcode

    1. namespace WF_SimpleDatabindingTxbx
    2. {
    3. public class MyModel :INotifyPropertyChanged
    4. {
    5. public MyModel()
    6. { }
    7. public MyModel(string name)
    8. {
    9. Name = name;
    10. }
    11. public event PropertyChangedEventHandler? PropertyChanged;
    12. private void NotifyPropertyChanged(string name)
    13. {
    14. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    15. }
    16. private string _name = "";
    17. public string Name
    18. {
    19. get { return _name; }
    20. set { _name = value; NotifyPropertyChanged(nameof(Name)); }
    21. }
    22. }
    23. }
    codewars.com Rank: 4 kyu

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „nogood“ ()

    Danke euch beiden!
    Für mein Projekt würde auch so was funktionieren. INotifyPropertyChange ist im Model implementiert ABER keine Backingfields (nur klassisch Propertys).
    Und in der Form falls ein Update passiert ist und angezeigt werden soll rufe ich das Event 'per Hand' auf.
    So wären meine Model-Klassen wieder schön (plus Basisklassen-Ansatz von @ISliceUrPanties wieder so wie früher :) ). Bin ich da auf einem Holzweg und übersehe größere Nachteile?


    Model:

    C#-Quellcode

    1. namespace WF_SimpleDatabindingNotifyChange
    2. {
    3. public class MyModel : INotifyPropertyChanged
    4. {
    5. public MyModel()
    6. { }
    7. public MyModel(string name)
    8. {
    9. Name = name;
    10. }
    11. public event PropertyChangedEventHandler? PropertyChanged;
    12. public void NotifyPropertyChanged(string nameOfProperty)
    13. {
    14. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameOfProperty));
    15. }
    16. public string Name { get; set; } = "";
    17. }
    18. }


    Form-UI:

    C#-Quellcode

    1. namespace WF_SimpleDatabindingNotifyChange
    2. {
    3. public partial class Form1 : Form
    4. {
    5. public MyModel MyModelObj { get; set; } = new("Tom");
    6. public Form1()
    7. {
    8. InitializeComponent();
    9. CenterToParent();
    10. textBox2.DataBindings.Add(new Binding("Text", MyModelObj, nameof(MyModel.Name), false, DataSourceUpdateMode.OnPropertyChanged));
    11. }
    12. private void button1_Click(object sender, EventArgs e)
    13. {
    14. MyModelObj.Name = textBox1.Text;
    15. MyModelObj.NotifyPropertyChanged(nameof(MyModel.Name));
    16. }
    17. }
    18. }
    codewars.com Rank: 4 kyu
    das snippet#1 wird nicht funktionieren.
    Also der Sinn des INotifyPropertyChanged-Interface ist doch, dass man das Event dann auch feuert, wenn eine Property changet.
    Tut deine Property Name aber nicht - denkst du das geht von selbst?

    Achso - nee - du rufst das Event dann aus dem Form-Code auf - Ja, da bist du auf dem Holzweg.
    Die Property muss das PropertyChanged aufrufen - nicht irgendwer anners.

    C#-Quellcode

    1. using System.ComponentModel;
    2. using System.Runtime.CompilerServices;
    3. namespace WF_SimpleDatabindingNotifyChange {
    4. public class MyModel : INotifyPropertyChanged {
    5. public MyModel() { }
    6. public MyModel(string name) {
    7. Name = name;
    8. }
    9. public event PropertyChangedEventHandler PropertyChanged;
    10. protected void NotifyPropertyChanged([CallerMemberName] string nameOfProperty = "") {
    11. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameOfProperty));
    12. }
    13. private string _Name = "";
    14. public string Name {
    15. get { return _Name; }
    16. set {
    17. if (_Name == value) return;
    18. _Name = value; NotifyPropertyChanged();
    19. }
    20. }
    21. }
    22. }
    Aber das müsste sich doch in jedem dahergelaufenem Tut über INotifyPropertyChanged in dieser Art so finden lassen.
    @ErfinderDesRades Danke das Du hier schreibst. Ja so wie Du das meinst hab ich es auch zuerst gemacht in Posting Nr. 3 (Deine Lösung ist noch eleganter :) ).
    Mir passt es aber nicht, dass die Model-Klassen so unansehnlich mit den ganzen private-Backingfields werden.

    Daher der zweite unorthodoxe Ansatz das PropertyChangeEvent per Hand aus der Form zu feuern. Dann können die Propertys so bleiben wie sie sonst sind ohne private-Field.
    Funktionieren tuts in meinem Projekt, mir fehlt aber die Weitsicht, ob das irgendwo anders Konsequenzen hat/Nachteile. Außer natürlich den offensichtlichen, dass ich selber auf passen muss wann das Event feuern soll.

    Lg
    codewars.com Rank: 4 kyu
    Dein Ansatz bringt Dir m.E. insofern nix, weil Du ja bei jeder möglichen Änderung eines Propertywerts das Event manuell feuern müsstest. Stell Dir z.B. ein DGV vor, in dem Daten vom User geändert werden können. Dann müsstest Du dort beim DgvCellEndEdit das Event feuern - abhängig davon, in welcher Spalte Du bist, ist eine andere Property betroffen. Spätestens hier wird klar, dass das in-der-Modelklasse-Feuern von Vorteil ist. Denn das wird control-unabhängig aufgerufen. Die Property wird eben automatisch informiert, wann sie geändert wird.
    Ich hatte mich vor längerer Zeit auch mal mit Verbesserungen der OnPropertyChanged-Situation beschäftigt. Ist im Sande verlaufen. Aber v.a. auch deshalb, weil ich irgendwann keinen Bock mehr hatte, weiterzusuchen :/
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    jo, ist nicht so schön. Man kann die Prop noch bisserl eindampfen auf einen 5-Zeiler:

    C#-Quellcode

    1. using System.ComponentModel;
    2. using System.Runtime.CompilerServices;
    3. namespace WF_SimpleDatabindingNotifyChange {
    4. public class MyModel : INotifyPropertyChanged {
    5. public MyModel() { }
    6. public MyModel(string name) {
    7. Name = name;
    8. }
    9. public event PropertyChangedEventHandler PropertyChanged;
    10. protected bool ChangePropIfDifferent<T>(ref T backingField, T newValue, [CallerMemberName] string nameOfProperty = "") {
    11. // (dieses sollte in eine BasisKlassse, die an alle Model-Klassen vererbt wird)
    12. if (object.Equals(backingField, newValue)) return false;
    13. backingField = newValue;
    14. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameOfProperty));
    15. return true;
    16. }
    17. private string _Name = "";
    18. public string Name {
    19. get { return _Name; }
    20. set { ChangePropIfDifferent(ref _Name, value); }
    21. }
    22. }
    23. }
    Ansonsten musste dich daran gewöhnen.
    Dein unkonventioneller Ansatz geeht zwar, ist aber nicht, was man von Databinding erwartet.