Laden...

Textbox Databinding: Nur die erste Änderung der Daten führt zu einer Aktualisierung des GUIs

Erstellt von Centrii vor 9 Jahren Letzter Beitrag vor 9 Jahren 3.192 Views
C
Centrii Themenstarter:in
30 Beiträge seit 2009
vor 9 Jahren
Textbox Databinding: Nur die erste Änderung der Daten führt zu einer Aktualisierung des GUIs

Hallo Zusammen,

ich versuche derzeit mehrere Textboxen mit Databinding zu versehen. Hierzu habe ich eine eigene Klasse mit Werten erstellt, die auch INotifyPropertyChanged enthält.
Mein Problem ist folgendes, ändere ich den Wert der Textbox in der GUI geht alles gut. Ändere ich den Wert meiner Klassenvariable, funktioniert das Binding genau einmal, danach nicht mehr.

Meine Klasse sieht beispielhaft so aus:


    class AktuelleWerte : INotifyPropertyChanged
    {
        private string sfillLeveltank;
        public string FillLeveltank_Anzeige
        {
            get { return sfillLeveltank; }
            set
            {
                sfillLeveltank = value;
                InvokePropertyChanged(new PropertyChangedEventArgs("FillLeveltank_Anzeige"));
            }
        }
 
        #region Implementation of INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        public void InvokePropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, e);
        }

        #endregion
    }


in meinem Form erstelle ich das Binding dann wie folgt:


_act = new AktuelleWerte();

tb_FilllevelTank.DataBindings.Add("Text", this._act, "FillLeveltank_Anzeige",false,DataSourceUpdateMode.OnPropertyChanged);


wenn ich nun z.B.

_act.FillLeveltank_Anzeige = fill.ToString() + " Liter";

aufrufe, wird der Wert in der Textbox einmal aktualisiert und danach nie wieder.
in meiner Klasse wird das Event gefeuert, aber es kommt nicht mehr an.

Hat einer eine Idee an was dies liegen könnte?

EDIT: das erste mal wo es funktioniert ist direkt nach dem Databinding noch innerhalb vom Form_Load. Danach geht es nicht mehr...

Bin für jede Hilfe dankbar.

Gruß
Centrii

Theorie ist, wenn man alles weiss, aber nichts funktioniert. Praxis ist, wenn alles funktioniert und keiner weiss warum

H
523 Beiträge seit 2008
vor 9 Jahren

Das Binding ist korrekt implementiert und funktioniert:


        AktuelleWerte _act = new AktuelleWerte();

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _act = new AktuelleWerte();
            tb_FilllevelTank.DataBindings.Add("Text", this._act, "FillLeveltank_Anzeige", false, DataSourceUpdateMode.OnPropertyChanged);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            _act.FillLeveltank_Anzeige = DateTime.Now.ToLongTimeString();
        }

Ich vermute, dass das Problem hier liegt:

_act.FillLeveltank_Anzeige = fill.ToString() + " Liter";

C
Centrii Themenstarter:in
30 Beiträge seit 2009
vor 9 Jahren

Hallo Hypersurf,

beim debuggen wird das OnPropertyChanged aber aufgerufen, d.h. die Textbox scheint das Event nicht zu bekommen...
Könnte es evtl. daran liegen das ich das Property in einem Timer aufrufe?
DoEvents() hilft auch nicht weiter, selbst wenn ich textbox.Databinding[0].Write/ReadValue aufrufe tut sich nichts...

Theorie ist, wenn man alles weiss, aber nichts funktioniert. Praxis ist, wenn alles funktioniert und keiner weiss warum

F
10.010 Beiträge seit 2004
vor 9 Jahren

DoEvents() ist ein aus VB6 herübergerettetes "Böse" das man eh nicht benutzen sollte.

Dein code sieht mir aber so aus als wenn du _act.FillLeveltank_Anzeige aus einem anderen Tread aufrufst, und das ist [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke)

C
Centrii Themenstarter:in
30 Beiträge seit 2009
vor 9 Jahren

über die Invoke Möglichkeit habe ich es bisher gemacht, wollte nun aber eigentlich auf das Databinding ausweichen, da ich dachte das ist Threadsafe, zumindest ist dies in WPF so, oder etwa nicht?

das würde aber heißen ich kan bei WinForms das Databinding nur im Hauptthread verwenden?

Theorie ist, wenn man alles weiss, aber nichts funktioniert. Praxis ist, wenn alles funktioniert und keiner weiss warum

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo Centrii,

alle GUI-Zugriffe müssen sowohl bei WPF als auch bei Windows Forms zwingend single-threaded realisiert sein. Das GUI ist in keiner Weise thread-safe.

Es ist, wie es in der FAQ steht:

Databinding: Zugriffe auf gebundene Daten

Nicht nur Zugriffe auf Controls selbst müssen aus dem GUI-Thread erfolgen. Auch alle Zugriffe auf andere Objekte/Daten müssen aus dem GUI-Thread erfolgen, nachdem diese mittels Databinding an Controls gebunden wurden. Das heißt, man kann durchaus eine aufwändige Liste in einem Worker-Thread füllen, aber sobald diese Liste an ein Control gebunden wurde, was natürlich im GUI-Thread erfolgen muss, müssen auch alle weiteren Zugriffe auf die Liste und/oder darin enthalte Objekte aus dem GUI-Thread erfolgen.

Dass das GUI single-threaded sein muss, gehört zu den elementaren und wichtigen Grundlagen, die wir als bekannt voraussetzen. Bitte beachte [Hinweis] Wie poste ich richtig? Punkt 1.1.1. Bitte stelle keine Fragen, die in der FAQ bereits (klar) beantwortet sind. Bitte beachte vor jeder (Nach-)Frage Punkt 1.1.

herbivore

C
Centrii Themenstarter:in
30 Beiträge seit 2009
vor 9 Jahren

sorry das ich mir den anderen Post nicht genau durchgelesen habe.

Ich habe meinen Timer jetzt mal deaktiviert und versuche über einen Button Werte zu schreiben, also im GUI-Thread. Leider funktioniert das auch nicht. das erste mal schreiben im Form_Load geht und danach geht es nicht mehr.

Prinzipiell ändere ich im TimerElapsed ja eine im GUI-Thread erstellte Klasse mit meinen Properties.
Das Event wird ja auch ausgelöst, gleich wie in dem Button Test. Hier wird das Event auch ausgelöst, leider wird die Textbox in beiden Fällen aber nicht mehr aktualisiert.

Theorie ist, wenn man alles weiss, aber nichts funktioniert. Praxis ist, wenn alles funktioniert und keiner weiss warum

S
145 Beiträge seit 2013
vor 9 Jahren

Probier mal eine BindingSource zwischen zu schalten

act=new AktuelleWerte();
bindignSource.DataSource=act;

((ISupportInitialize)bindignSource).BeginInit();

tb_FilllevelTank.DataBindings.Add("Text", bindignSourcet, "FillLeveltank_Anzeige",false,DataSourceUpdateMode.OnPropertyChanged);

((ISupportInitialize)bindignSource).EndInit();

(bissl ausm kopf getippt)

H
523 Beiträge seit 2008
vor 9 Jahren

Ich habe meinen Timer jetzt mal deaktiviert und versuche über einen Button Werte zu schreiben, also im GUI-Thread. Leider funktioniert das auch nicht. das erste mal schreiben im Form_Load geht und danach geht es nicht mehr.

Bitte poste den neuen Code der nicht funktioniert.

2.298 Beiträge seit 2010
vor 9 Jahren

Hallo Centrii,

was für einen Timer nutzt du denn genau? Den System.Windows.Forms Timer oder einen der anderen aus dem Namespace System.Threading?

Ansonste, sollte es nicht am Timer liegen weise ich nochmal auf die erste Antwort von hypersurf hin. Windows Forms mag es nicht, wenn trotz DataBinding noch manuell per Code Texte in Controls geändert werden.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo inflames2k,

ein Timer.Elapsed-Ereignis gibt es nur bei System.Timers.Timer. Bei System.Windows.Forms.Timer heißt das Event Tick. Und bei System.Threading.Timer gibt es gar kein Event, sondern dort übergibt man stattdessen einen Callback-Delegaten an den Konstruktor.

Hallo Centrii,

für Windows-Forms-Programme sollte man normalerweise System.Windows.Forms.Timer benutzen, wenn es darum geht, einen GUI-Zugriff durchzuführen, denn das Tick-Event läuft automatisch im GUI-Thread.

Was hast du denn im Debugger (siehe [Artikel] Debugger: Wie verwende ich den von Visual Studio?) bzw. mit entsprechenden Log-Ausgaben über die tatsächlichen Abläufe herausgefunden?

Bitte beachte auch, was meine Vorredner geraten/gefordert haben.

herbivore