Update DGV über BindingSource

  • VB.NET

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

    Update DGV über BindingSource

    Hi,

    ich habe eine List(of ...) an eine Binding Source gebunden. (Einige werden sich an mein früheres Posting erinnern. :) )

    so sieht das aus:

    VB.NET-Quellcode

    1. Public Class Transponder
    2. Property Seq As Integer
    3. Property Lvl As Integer
    4. Property Tag As String
    5. End Class
    6. Public TransponderList As New List(Of Transponder)
    7. Dim BindingSource1 As New BindingSource
    8. ...
    9. BindingSource1.Add(New Transponder With {.Seq = cnt, .Lvl = lvl, .Tag = indent & line})
    10. ...
    11. dgvTransponder.DataSource = BindingSource1


    Das funktioniert auch alles (Dank eurer unschätzbaren Hilfe) wunderbar !

    Jetzt möchte ich einzelne Zeilen verändern. Das geschieht über ein Eingabefeld "txtTag" und dem Button "cmdReplace"

    VB.NET-Quellcode

    1. Private Sub cmdTagReplace_Click(sender As Object, e As EventArgs) Handles cmdTagReplace.Click
    2. TransponderList(i).Tag = txtTag.Text 'Replace Tag


    Das läuft auch fehlerfrei durch.

    Naiv wie ich nun mal bin, hätte ich jetzt vermutet, dass die DGV automatisch mit geändert wird. Das ist aber nicht der Fall ! Die DGV bleibt unverändert.

    Die Änderung kommt aber in der TransponderList an. Denn wenn ich die DGV neu verbinde, wird die Änderung sichtbar 1

    Muss ich da einen "Refresh" oder "Reload" auslösen ? Ich würde allerding ITOP und SELECTEDROWS beibehalten ... NHatürlch kann ich das programmtechnisch realisieren ... aber ich meine, das Databinding soll mich ja gerade von solchen unnützen Arbeiten frei halten ...

    Ich hoffe, ihr könnt mir das (nachsichtig wie immer) beibringen.

    LG
    Peter
    Hey,

    wer oder was informiert denn die BindingSource oder das DataGridView über änderungen?
    ->In deinem Code nichts.

    Man fummelt auch nicht an der unterliegenden Daten herum. Das macht man alles über die BindingSource!

    C#-Quellcode

    1. Transponder t = (Transponder)BS.Current;
    2. t.Tag = "Oh, that's the way!";
    3. BS.ResetCurrentItem();

    seh ich genau andersrum: Man fummelt nicht im Gui herum, wenn man Daten ändern will.



    Was hier fehlt ist eine Implementation der INotifyPropertyChanged-Schnittstelle in der DatenKlasse.
    INotifyPropertyChanged ist der Mechanismus, mit dem bei Datebinding das Gui von Änderungen unterrichtet wird.

    Wie gelegentlich erwähnt: Son typDataset hat wirklich 'ne Menge drinne, was man alles händisch neu erfinden muss, wenn man mit selbstgebastelten Klassen rumwerkeln möchte.

    ErfinderDesRades schrieb:

    seh ich genau andersrum: Man fummelt nicht im Gui herum, wenn man Daten ändern will.


    Was spricht dagegen ein Form mit Controls zu nutzen um einen Datensatz zu editieren? Das mach ich immer über Bindung. Im DataGridView selbst lasse ich in meinen Tools keine Bearbeitung zu.
    Oder habe ich dich falsch verstanden?

    Eine BindingSource sehe ich jetzt nicht als GUI, ich nutze sonst auch keine List<t> als DataSouce, da ziehe ich das DataSet vor. Vermutlich konnte ich dir wirklich nicht folgen...

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Takafusa“ ()

    Ich binde die TextBox.Text-Property an die bei der BS hinterlegten passenden Property der Datenliste -> kein Code mehr nötig.
    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.
    @Takafusa

    Irgendwie habe ich Schwierigkeiten deinen C# Code in VB.Net umzusetzen. So habe ich das (u.a.) versucht:

    VB.NET-Quellcode

    1. Dim t = BindingSource1.Current
    2. t.Tag = myIndent & txtTag.Text 'Replace Tag
    3. BindingSource1.ResetCurrentItem()


    Klar, "t" hat den Typ Object ... und da gibt es keine Property "Tag" ... ich krieg einfach die Zuweisung von BindingSource1.Current nicht gebacken ...

    Oder wie würde ich das mit der von @VaporiZed bzw. @EDR vorgeschlagenen Technik machen ?

    Ich verstehe langsam schon, dass ein DataSet eine Menge Vorteile hat. Aber jetzt würde ich mein Programm halt nicht "umwerfen" wollen. Das nächste Mal, folge ich dann der Empfehlung. :)

    LG
    Peter

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

    Habe das jetzt flott über Bindung gemacht.
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Diagnostics;
    6. using System.Drawing;
    7. using System.Linq;
    8. using System.Text;
    9. using System.Threading.Tasks;
    10. using System.Windows.Forms;
    11. namespace WindowsFormsApp1
    12. {
    13. public partial class Form1 : Form
    14. {
    15. BindingSource BS = new BindingSource();
    16. List<Transponder> TransponderList = new List<Transponder>();
    17. public Form1()
    18. {
    19. InitializeComponent();
    20. }
    21. private void Form1_Load(object sender, EventArgs e)
    22. {
    23. BS.DataSource = TransponderList;
    24. dataGridView1.DataSource = BS;
    25. for(int i = 0; i < 10; i++)
    26. {
    27. BS.Add(new Transponder() { Seq = (i * i), Lvl = i, Tag = (i * i).ToString() });
    28. }
    29. textBox1.DataBindings.Add(new Binding("Text", BS, "Tag", false, DataSourceUpdateMode.OnPropertyChanged));
    30. }
    31. class Transponder
    32. {
    33. public int Seq { get; set; }
    34. public int Lvl { get; set; }
    35. public string Tag { get; set; }
    36. }
    37. }
    38. }


    Zu Peters Frage:

    VB.NET-Quellcode

    1. Dim t as Transponder = Directcast(BindingSource1.Current, Transponder)
    2. t.Tag = myIndent & txtTag.Text 'Replace Tag
    3. BindingSource1.ResetCurrentItem()




    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Takafusa“ ()

    advanced topic/advertisement: man ersetze eine normale BS durch eine typisierte BindingSource und das Casting ist beendet überflüssig :rolleyes:
    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.

    Takafusa schrieb:

    ErfinderDesRades schrieb:

    seh ich genau andersrum: Man fummelt nicht im Gui herum, wenn man Daten ändern will.

    Eine BindingSource sehe ich jetzt nicht als GUI, ...
    Jo - ich hab auch überspitzt formuliert.
    Weil manchmal gehts nicht anders, dann muss mans eben so machen, wie es geht.

    Ich betrachte das als Schichten-Architektur:
    1. Daten
    2. BindingSources
    3. Controls

    Codeseitige Datenverarbeitung sollte
    1. vorrangig an den Daten ansetzen (Databinding kümmert sich dann drum, dass die anderen Schichten "mitkommen")
    2. Nachrangig in der BindingSource-Schicht.
    3. Noch nachrangiger in den Controls.

    Vorteile sind die üblichen Vorteile von Schichten-Architektur:
    • Man kann die höheren Schichten modifizieren, ohne das darunter liegende anfassen zu müssen.
    • Man kann Code sinnvoll aufteilen
      etwa Daten-Operationen mache ich im Daten-Bereich, meist in partialen Dataset-Klassen. Das entlastet den Form-Code ungemein.

    Der Zugriff über BindingSources ist (zwar nicht schön, aber) einheitlich. Hingegen die Items, SelectedItems von Combo-/List-Box oder DGV abzurufen ist jeweils speziell.

    Aber wie gesagt: Es geht nur, was geht.
    Gelegentlich reicht das Instrumentarium der tieferen Schicht nicht aus, dann muss man halt widerwillig eine höhere bemühen.



    Nochmal zu INotifyPropertyChanged: Die Datenklasse müsste so aussehen:

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Imports System.Runtime.CompilerServices
    3. Public Class Transponder : Implements INotifyPropertyChanged
    4. Private _Seq As Integer
    5. Public Property Seq() As Integer
    6. Get
    7. Return _Seq
    8. End Get
    9. Set(ByVal value As Integer)
    10. ChangePropIfDifferent(value, _Seq)
    11. End Set
    12. End Property
    13. Private _Lvl As Integer
    14. Public Property Lvl() As Integer
    15. Get
    16. Return _Lvl
    17. End Get
    18. Set(ByVal value As Integer)
    19. ChangePropIfDifferent(value, _Lvl)
    20. End Set
    21. End Property
    22. Private _Tag As String
    23. Public Property Tag() As String
    24. Get
    25. Return _Tag
    26. End Get
    27. Set(ByVal value As String)
    28. ChangePropIfDifferent(value, _Tag)
    29. End Set
    30. End Property
    31. Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    32. Private Sub ChangePropIfDifferent(Of TProp)(value As TProp, ByRef backingField As TProp, <CallerMemberName> Optional name As String = "")
    33. If Object.Equals(backingField, value) Then Return
    34. backingField = value
    35. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
    36. End Sub
    37. End Class
    Dann würde der Code aus post#1 ohne Änderung das machen, was gedacht.

    Zur INotifyPropertyChanged-Implementation: Das ist jetzt nur ein einfaches Sample, ohne ausgelagerten Infrastruktur-Code.
    Man sollte nämlich bischen Infrastruktur schreiben - eine Basisklasse, von der alle Datenklassen erben - dann wird das bischen einfacher.
    Und dann kann man der Basisklasse auch noch paar weitere nützliche Features angedeihen lassen.

    Aber eine gewisse Umständlichkeit kriegt man nicht weg, weil nämlich AutoProperties (wie in post#1) kann man in Databinding-Szenarien nicht verwenden.

    ErfinderDesRades schrieb:

    Die Datenklasse müsste so aussehen
    Minimale Vereinfachung:
    Set(ByVal value As String) -> Set. Geht bei allen gezeigten Properties.
    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.