none
Zeile eines DataGridViews in einem separaten Formular anzeigen und bearbeiten RRS feed

  • Frage

  • Hallo zusammen,

    ich habe das Problem, dass Daten einer SQL-Tabelle in komprimierter Form in einem DataGridView angezeigt werden, die Daten selbst aber vollständig nach Auswahl einer konkreten Zeile des DataGridViews in einem separaten Formular angezeigt und bearbeitet werden sollen.

    Bisher habe ich das Problem so gelöst, dass ich die entsprechenden Daten 1:1 manuell an das weitere Formular übergeben habe und den einzelnen Textboxen die einzelnen Werte des Datensatzes übergeben habe. Funktioniert zwar für die reine Datenanzeige, doch wenn sie die Daten ändern, muss ich die einzelnen Textboxen vor dem Schließen des Formular wieder auslesen und an das Ursprungsformular zurückgeben.

    Grob zusammengefasst gehe ich wie folgt vor (auf das manuelle Anpassen des DataGridView sowie dem Ausblenden einzelnen Spalten habe ich verzichtet)

      ' Auslesen der Daten und zuweisen dieser an das zugehörige Datagridview
    
      Private FristenDataSet As DataSet
      Private FristenBindingSource As BindingSource
    
      Me.FristenDataSet = New DataSet("Fristen")
      Me.FristenDataSet.Tables.Add(Me.GetFristen())
      Me.FristenBindingSource = New BindingSource(Me.FristenDataSet, "Details")
      Me.FristenDataGridView.DataSource = Me.FristenBindingSource
    
      ' Das Bearbeiten der entsprechenden Zeile des DataGRidView habe ich über ein ContextMenü wie folgt realisiert:
    
      Private Sub FristBearbeitenToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles FristBearbeitenToolStripMenuItem.Click, FristBearbeitenToolStripContextMenuItem.Click, fristenDataGridView.DoubleClick
    
        ' Bestehende Frist bearbeiten
    
        Try
          If (Me.fristenDataGridView.Rows.Count > 0) Then
            If (Me.fristenDataGridView.SelectedRows.Count = 1) Then
              Dim actFristRow, modifiedFristRow As DataRow
              Dim locFristenForm As New FristenBearbeiten()
    
              actFristRow = Utilities.Konvertierungen.ConvertDataGridViewRowToDataRow(Me.fristenDataGridView.SelectedRows(0))
              modifiedFristRow = locFristenForm.AlterFrist(actFristRow, Me.mIniPflege)
    
              If Not (modifiedFristRow Is Nothing) Then
                modifiedFristRow.Item("ÄnderungsKennung") = Me.Bearbeiter.Kennung
                modifiedFristRow.Item("ÄnderungsDatum") = Now
              End If
            End If
          Else
            MsgBox("Zu dem angegebenen Fall sind momentan noch keine " & vbCrLf & _
                "Termine / Fristen hinterlegt. " & vbCrLf & vbCrLf & _
                "Die gewünschte Aktion kann daher nicht ausgeführt werden !" & vbTab, MsgBoxStyle.Information, " Hinweis")
          End If
        Catch ex As Exception
          MsgBox(ex.ToString())
        End Try
      End Sub
    Ich finde diese vorgehensweise nicht ganz optimal. Vor allem da der Datentabelle sehr viele Spalten beinhaltet bin ich für jeden Tip dankbar, wie man das Ganze einfacher und übersichtlicher gestalten könnte.

    Mittwoch, 22. September 2010 13:37

Antworten

  • Hallo,

    Am einfachsten: Übergib der Detail-Form im Konstruktor eine Referenz auf Deine BindingSource und binde an den aktuellen Datensatz. Das DataGridView ist nur die Anzeigeoberfläche, was zählt sind die zugrundeliegenden Daten. Alle Datenmanipulation sollte auf der Datenebene stattfinden.

    Gruß
    Marcel

    Donnerstag, 23. September 2010 07:03
  • Hallo V.,

    auch von meiner Seite: nutze möglichst einen gemeinsamen BindingSource der Formen, das hat am meisten Vorteile.
    Dabei braucht man natürlich nicht unbedingt eine Übergabe über den Konstruktor sondern kann auch den BindingSource öffentlich machen (oder public static) machen, dann kann man entweder über "MainForm.MyBindingSource" oder die MainForm-Instanz einfach daran binden.
    Wie auch immer - Hauptsache, der genutzte BindingSource ist auf die gleiche Referenz gesetzt.


    ciao Frank
    Donnerstag, 23. September 2010 08:03
  • Hallo,

    ich habe das Problem, dass Daten einer SQL-Tabelle in komprimierter
    Form in einem DataGridView angezeigt werden, die Daten selbst aber
    vollständig nach Auswahl einer konkreten Zeile des DataGridViews in
    einem separaten Formular angezeigt und bearbeitet werden sollen.

    Bisher habe ich das Problem so gelöst, dass ich die entsprechenden
    Daten 1:1 manuell an das weitere Formular übergeben habe und den
    einzelnen Textboxen die einzelnen Werte des Datensatzes übergeben
    habe. Funktioniert zwar für die reine Datenanzeige, doch wenn sie
    die Daten ändern, muss ich die einzelnen Textboxen vor dem
    Schließen des Formular wieder auslesen und an das
    Ursprungsformular zurückgeben.

    Du musst nur Dein DataGridView und Deine Textboxen an die
    selbe Datenquelle (DataTable/DataView oder Bindingsource)
    binden.

    Hier ein Beispiel:
    Erstelle ein neues Projekt mit einer leeren Form1 (Form1.vb)
    und einer leeren Form2 (Form2.vb). Kopiere nachfolgenden
    Code in die Formmodule Form1.vb bzw. Form2.vb

    ' / Code in Form1.vb
    Public Class Form1
        Private WithEvents DGV As DataGridView
        Private mDT As DataTable
        Private WithEvents mBS As BindingSource

        Private Sub Form1_Load _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles Me.Load

            DGV = New DataGridView
            With DGV
                .Dock = DockStyle.Fill

                .DefaultCellStyle.Font = _
                        New Font("Arial", 12)

                .ColumnHeadersDefaultCellStyle.Font = _
                        New Font("Arial", 8, FontStyle.Bold)

            End With
            Me.Controls.Add(DGV)

            CreateData()

            With DGV
                .DataSource = mBS

                .Columns(0).DefaultCellStyle.Alignment = _
                        DataGridViewContentAlignment.MiddleRight

                .AutoResizeColumns()

                .AllowUserToAddRows = False
                .ReadOnly = True
            End With

            Me.Height = 400

        End Sub

        Private Sub CreateData()
            Dim i As Integer
            Dim DR As DataRow

            mDT = New DataTable
            With mDT
                .Columns.Add("ID", GetType(Integer))
                .Columns.Add("SText", GetType(String))
                .Columns.Add("LText", GetType(String))

                For i = 1 To 12
                    DR = .NewRow
                    DR.Item(0) = i
                    DR.Item(1) = MonthName(i, True)
                    DR.Item(2) = MonthName(i, False)
                    .Rows.Add(DR)
                Next
                .AcceptChanges()
            End With

            mBS = New BindingSource
            mBS.DataSource = mDT
        End Sub

        Private Sub Form1_Shown _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles Me.Shown

            Form2.Show(Me)
            Form2.BS = mBS
        End Sub

        Private Sub mBS_ListChanged _
                (ByVal sender As Object, _
                 ByVal e As System.ComponentModel.ListChangedEventArgs _
                 ) Handles mBS.ListChanged

            If e.ListChangedType = System.ComponentModel.ListChangedType.ItemAdded Then
                DGV.Refresh()
            End If
        End Sub

    End Class
    ' \\\ Ende Form1.vb
    ' ##############

    ' ##############
    ' / Code in Form2.vb
    Public Class Form2
        Private WithEvents txtID As TextBox
        Private WithEvents txtLText As TextBox
        Private WithEvents mOF As Form1
        Private WithEvents mBS As BindingSource

        Friend Property BS() As BindingSource
            Get
                Return mBS
            End Get
            Set(ByVal value As BindingSource)
                mBS = value
            End Set
        End Property

        Private Sub Form2_Load _
                (ByVal sender As System.Object, _
                 ByVal e As System.EventArgs _
                ) Handles MyBase.Load

            mOF = DirectCast(Me.Owner, Form1)

            CreateControls()
        End Sub

        Private Sub NavButton_Click _
                (ByVal sender As System.Object, _
                 ByVal e As System.EventArgs)

            txtLText.Focus()
            Select Case DirectCast(sender, Button).Name
                Case "btnFirst"
                    mBS.Position = 0
                Case "btnPrevious"
                    mBS.Position -= 1
                Case "btnNext"
                    mBS.Position += 1
                Case "btnLast"
                    mBS.Position = mBS.Count - 1
                Case "btnNew"
                    mBS.AddNew()
                    txtID.Focus()
            End Select
        End Sub

        Private Sub CreateControls()
            Dim i As Integer
            Dim BtnNames() As String
            Dim BtnText() As String

            txtID = New TextBox
            With txtID
                .Name = "txtID"
                .Font = New Font("Arial", 14)
                .SetBounds(10, 15, 50, .Height)
            End With
            Me.Controls.Add(txtID)

            txtLText = New TextBox
            With txtLText
                .Name = "txtLText"
                .Font = txtID.Font

                .SetBounds _
                    (txtID.Right + 3, txtID.Top, _
                     180, .Height)

            End With
            Me.Controls.Add(txtLText)

            Me.ClientSize = _
                    New Size _
                        (txtLText.Right + 10, _
                         txtLText.Bottom + 75)

            txtLText.Anchor = _
                    AnchorStyles.Left Or _
                    AnchorStyles.Top Or _
                    AnchorStyles.Right

            BtnNames = _
                New String() _
                {"btnFirst", "btnPrevious", "btnNext", "btnLast", "btnNew"}

            BtnText = New String() {"|<", "<", ">", ">|", ">||"}

            Dim Left As Integer = txtID.Left
            Dim Top As Integer = txtLText.Bottom + 20
            Dim Btn As Button

            For i = 0 To BtnNames.GetUpperBound(0)
                Btn = New Button
                With Btn
                    .Name = BtnNames(i)
                    .Font = New Font("Arial", 12, FontStyle.Bold)
                    .Text = BtnText(i)
                    .SetBounds(Left, Top, 40, 40)
                End With
                Me.Controls.Add(Btn)
                AddHandler Btn.Click, AddressOf NavButton_Click
                Left = Btn.Right + 2
            Next

        End Sub

        Private Sub BindControls()
            Dim B As Binding

            B = New Binding _
                    ("Text", mBS, "ID", True, _
                     DataSourceUpdateMode.OnPropertyChanged)

            DirectCast _
                    (Me.Controls("txtID"),  _
                    TextBox).DataBindings.Add(B)

            B = New Binding _
                    ("Text", mBS, "LText", True, _
                     DataSourceUpdateMode.OnPropertyChanged)

            DirectCast _
                    (Me.Controls("txtLText"),  _
                    TextBox).DataBindings.Add(B)

        End Sub

        Private Sub Form2_Shown _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles Me.Shown

            Dim F As Form = Me.Owner

            Me.Width = F.Width
            Me.Location = New Point(F.Left, F.Bottom)
            BindControls()
        End Sub

        Private Sub mOF_LocationChanged _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles mOF.LocationChanged

            Me.Location = New Point(mOF.Left, mOF.Bottom)
        End Sub

        Private Sub txtID_TextChanged _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles txtID.TextChanged

            Dim DRV As DataRowView = _
                    DirectCast(mBS.Current, DataRowView)

            If DRV.IsEdit Then
                Dim Value As Integer
                If Integer.TryParse(txtID.Text, Value) Then
                    DRV.Row.Item(0) = Value
                Else
                    DRV.Row.Item(0) = DBNull.Value
                End If
            End If
            mBS.EndEdit()
        End Sub

        Private Sub txtLText_TextChanged _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles txtLText.TextChanged

            Dim DRV As DataRowView = _
                    DirectCast(mBS.Current, DataRowView)

            If DRV.IsEdit Then
                DRV.Row.Item(2) = txtLText.Text
            End If
            mBS.EndEdit()
        End Sub

    End Class
    ' \\\ Ende Form2.vb

    Nach dem Programmstart siehst Du Form1 mit dem DGV
    und Form2 mit den Textboxen und Buttons zum Navigieren
    im Datenbestand.

    Die Dateneingabe erfolgt in den Textboxen der Form2.
    Jede Eingabe wird zeitgleich im DGV der Form1 sichtbar.

    Gruß aus St.Georgen
    Peter Götz
    www.gssg.de (mit VB-Tipps u. Beispielprogrammen)

    Donnerstag, 23. September 2010 17:46
  • Hallo Martin,

    Ich kann mir leider nicht vorstellen, was noch so in Deinem Code drin steht. Darum würde ich Dich bitten, Dir folgenden Code anzusehen um dann evtl. festzustellen, was genau an Deinem Code anders ist:

    Form1:

    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;
    
    namespace RefreshDataGridView
    {
      public partial class Form1 : Form
      {
        BindingSource bindingSource = new BindingSource();
    
        public Form1()
        {
          InitializeComponent();
        }
    
        private void Form1_Load(object sender, EventArgs e)
        {
          List<Person> persons = new List<Person> 
          { 
            new Person { Nachname = "Doe", Vorname = "John"},
            new Person { Nachname = "Doe", Vorname = "Jane"}
          };
    
          bindingSource.DataSource = persons;
          dataGridView1.DataSource = bindingSource;
        }
    
        private void buttonDetails_Click(object sender, EventArgs e)
        {
          bindingSource.AddNew();
    
          Form2 f2 = new Form2(bindingSource);
          f2.ShowDialog();
        }
      }
    
      public class Person
      {
        public string Vorname { get; set; }
        public string Nachname { get; set; }
      }
    }
    
    

    Form2:

    using System;
    using System.Windows.Forms;
    
    namespace RefreshDataGridView
    {
      public partial class Form2 : Form
      {
        private BindingSource m_BindingSource;
        
        public Form2(BindingSource bindingSource)
        {
          m_BindingSource = bindingSource;
          InitializeComponent();
        }
    
        public Form2() : this(null)
        {
        }
    
        private void Form2_Load(object sender, EventArgs e)
        {
          if (m_BindingSource != null)
          {
            bindingNavigator1.BindingSource = m_BindingSource;
            textBox1.DataBindings.Add(new Binding("Text", m_BindingSource, "Vorname", true, DataSourceUpdateMode.OnPropertyChanged));
            textBox2.DataBindings.Add(new Binding("Text", m_BindingSource, "Nachname", true, DataSourceUpdateMode.OnPropertyChanged));
          }
        }
      }
    }
    
    

    (Ist zwar C#, bin mir aber ziemlich sicher, dass Du's nachvollziehen kannst.)

    Gruß
    Marcel

    Donnerstag, 23. September 2010 13:03

Alle Antworten

  • Hallo,

    Am einfachsten: Übergib der Detail-Form im Konstruktor eine Referenz auf Deine BindingSource und binde an den aktuellen Datensatz. Das DataGridView ist nur die Anzeigeoberfläche, was zählt sind die zugrundeliegenden Daten. Alle Datenmanipulation sollte auf der Datenebene stattfinden.

    Gruß
    Marcel

    Donnerstag, 23. September 2010 07:03
  • Hallo V.,

    auch von meiner Seite: nutze möglichst einen gemeinsamen BindingSource der Formen, das hat am meisten Vorteile.
    Dabei braucht man natürlich nicht unbedingt eine Übergabe über den Konstruktor sondern kann auch den BindingSource öffentlich machen (oder public static) machen, dann kann man entweder über "MainForm.MyBindingSource" oder die MainForm-Instanz einfach daran binden.
    Wie auch immer - Hauptsache, der genutzte BindingSource ist auf die gleiche Referenz gesetzt.


    ciao Frank
    Donnerstag, 23. September 2010 08:03
  • Hallo Marcel,

    Hallo Frank,

    vielen Dank für euren wertvollen Hinweis. Der Tip mit der Referenz auf meine BindingSource im Konstruktor hat fehlerfrei funktioniet. Auch ist der QuellCode erfreulicherweise um einiges geschrumpft. Das Bearbeiten und Löschen von Datensätzen funktioniert fehlerfrei, lediglich beim Erfassen eines neuen Datensatzes werden mir die Daten erst vollständig im DataGridView angezeigt, wenn ich eine andere als die gerade hinzugefügte Zeile des DataGridView auswähle. Ansonsten wird nur der Wert einzelner Spalten angezeigt. Eine Logik konnte ich bisher nicht erkennen. Habt ihr vielleicht noch einen Tipp, wie ich dieses kleine Problem beheben kann?

    Viele Grüße,

    Martin

    Donnerstag, 23. September 2010 10:16
  • Hallo Martin,

    Ich weiß nicht, auf welcher Seite Du die Daten einfügst. Wenn Du das über die Detail-Form machst, dann hilft es vielleicht das Binding so zu machen:

    textBox1.DataBindings.Add(new Binding("Text", m_BindingSource, "Vorname", true, DataSourceUpdateMode.OnPropertyChanged));
    textBox2.DataBindings.Add(new Binding("Text", m_BindingSource, "Nachname", true, DataSourceUpdateMode.OnPropertyChanged));
    
    

    Vielleicht steht auch nocht etwas aus der alten (entfernten) Logik im Weg.

    Gruß
    Marcel

    Donnerstag, 23. September 2010 11:08
  • Hallo Marcel,

    im Grunde gehe ich wie folgt vor. Bevor ich die Daten im Detail-Form erfasse füge ich meiner BindingSource im Haupt-Form mittels

    Me.FristenBindingSource.AddNew() 
    

    ein neues Element hinzu. Meine BindingSource übergebe ich dann wie gehabt als Referenz ans Detail-Form, wo das entsprechende DataBinding an die einzelnen Controls erfolgt. Leider hat auch Dein Vorschlag nicth zur Lösung des Problems geführt.

    Was ich merkwürdig finde ist, dass der neue Datensatz nur dann richtig im DataGridView angezeigt wird, wenn ich abschließend folgende CodeZeilen einfüge:

    Me.FristenDataGridView.Rows(Me.FristenDataGridView.Rows.Count - 1).Selected = True
    Me.FristenDataGridView.Rows(Me.FristenDataGridView.Rows.Count - 1).Selected = False
    
    

    Alte Programmlogik existiert auch keine mehr. Somit kann ich mir das Verhalten immer noch nicht erklären.

    Viele Grüße,

    Martin

    Donnerstag, 23. September 2010 12:42
  • Hallo Martin,

        > funktioniert fehlerfrei ...

    das freut mich.


    > lediglich beim Erfassen eines neuen Datensatzes werden mir die Daten erst vollständig im
    > DataGridView angezeigt, wenn ich eine andere als die gerade hinzugefügte Zeile des
    > DataGridView auswähle. Ansonsten wird nur der Wert einzelner Spalten angezeigt.
    > Eine Logik konnte ich bisher nicht erkennen. Habt ihr vielleicht noch einen Tipp,
    > wie ich dieses kleine Problem beheben kann?

    Ach, Du meinst, wenn Du den Satz programmatisch hinzugefügt hast.
    Neben dem UpdateMode ist es häufig die Ursache, dass man kein "bindingSource.EndEdit()" (o.ä.) gemacht hat.

    [Forcing a DataGridView to update values]


    ciao Frank
    Donnerstag, 23. September 2010 12:44
  • Hallo Frank,

    die Methode EndEdit() der zugehörigen BindingSource habe ich bereits fest im QuellCode verankert.
    Somt kann das erstmal als Ursache ausgeschlossen werden.

    Grüße,

    Martin
    Donnerstag, 23. September 2010 12:58
  • Hallo Martin,

    hast Du mit "bindingSource.AddNew" hinzugefügt?


    ciao Frank
    Donnerstag, 23. September 2010 13:00
  • Hallo Martin,

    Ich kann mir leider nicht vorstellen, was noch so in Deinem Code drin steht. Darum würde ich Dich bitten, Dir folgenden Code anzusehen um dann evtl. festzustellen, was genau an Deinem Code anders ist:

    Form1:

    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;
    
    namespace RefreshDataGridView
    {
      public partial class Form1 : Form
      {
        BindingSource bindingSource = new BindingSource();
    
        public Form1()
        {
          InitializeComponent();
        }
    
        private void Form1_Load(object sender, EventArgs e)
        {
          List<Person> persons = new List<Person> 
          { 
            new Person { Nachname = "Doe", Vorname = "John"},
            new Person { Nachname = "Doe", Vorname = "Jane"}
          };
    
          bindingSource.DataSource = persons;
          dataGridView1.DataSource = bindingSource;
        }
    
        private void buttonDetails_Click(object sender, EventArgs e)
        {
          bindingSource.AddNew();
    
          Form2 f2 = new Form2(bindingSource);
          f2.ShowDialog();
        }
      }
    
      public class Person
      {
        public string Vorname { get; set; }
        public string Nachname { get; set; }
      }
    }
    
    

    Form2:

    using System;
    using System.Windows.Forms;
    
    namespace RefreshDataGridView
    {
      public partial class Form2 : Form
      {
        private BindingSource m_BindingSource;
        
        public Form2(BindingSource bindingSource)
        {
          m_BindingSource = bindingSource;
          InitializeComponent();
        }
    
        public Form2() : this(null)
        {
        }
    
        private void Form2_Load(object sender, EventArgs e)
        {
          if (m_BindingSource != null)
          {
            bindingNavigator1.BindingSource = m_BindingSource;
            textBox1.DataBindings.Add(new Binding("Text", m_BindingSource, "Vorname", true, DataSourceUpdateMode.OnPropertyChanged));
            textBox2.DataBindings.Add(new Binding("Text", m_BindingSource, "Nachname", true, DataSourceUpdateMode.OnPropertyChanged));
          }
        }
      }
    }
    
    

    (Ist zwar C#, bin mir aber ziemlich sicher, dass Du's nachvollziehen kannst.)

    Gruß
    Marcel

    Donnerstag, 23. September 2010 13:03
  • Hallo Frank,

    Me .FristenBindingSource.AddNew() hab ich aufgerufen.

    Viele Grüße,

    Martin

    Donnerstag, 23. September 2010 13:08
  • ok,

    es könnte dann daran liegen:

    [ADO.Net databinding - BindingSource.EndEdit() changes current position - Stack Overflow]
    http://stackoverflow.com/questions/686597/ado-net-databinding-bug-bindingsource-endedit-changes-current-position

    also ggf. als Workaround:

       
    [...] 
            bindingSource
    .ListChanged +=  
               
    new ListChangedEventHandler(PreserveCurrentPosition); 
       
    [...] 
     
     
       
    private void PreserveCurrentPosition(object sender, ListChangedEventArgs e) 
       
    { 
           
    if (e.ListChangedType == System.ComponentModel.ListChangedType.ItemAdded && 
               
    ((BindingSource)sender).Count - e.NewIndex > 1) 
           
    { 
               
    ((BindingSource)sender).Position = e.NewIndex; 
           
    } 
       
    } 


    ciao Frank
    Donnerstag, 23. September 2010 15:30
  • ok,

    es könnte dann daran liegen:

    [ADO.Net databinding - BindingSource.EndEdit() changes current position - Stack Overflow]
    http://stackoverflow.com/questions/686597/ado-net-databinding-bug-bindingsource-endedit-changes-current-position

    also ggf. als Workaround:

       
    [...] 
            bindingSource
    .ListChanged +=  
               
    new ListChangedEventHandler(PreserveCurrentPosition); 
       
    [...] 
     
     
       
    private void PreserveCurrentPosition(object sender, ListChangedEventArgs e) 
       
    { 
           
    if (e.ListChangedType == System.ComponentModel.ListChangedType.ItemAdded && 
               
    ((BindingSource)sender).Count - e.NewIndex > 1) 
           
    { 
               
    ((BindingSource)sender).Position = e.NewIndex; 
           
    } 
       
    } 


    ciao Frank
    Donnerstag, 23. September 2010 15:31
  • Hallo,

    ich habe das Problem, dass Daten einer SQL-Tabelle in komprimierter
    Form in einem DataGridView angezeigt werden, die Daten selbst aber
    vollständig nach Auswahl einer konkreten Zeile des DataGridViews in
    einem separaten Formular angezeigt und bearbeitet werden sollen.

    Bisher habe ich das Problem so gelöst, dass ich die entsprechenden
    Daten 1:1 manuell an das weitere Formular übergeben habe und den
    einzelnen Textboxen die einzelnen Werte des Datensatzes übergeben
    habe. Funktioniert zwar für die reine Datenanzeige, doch wenn sie
    die Daten ändern, muss ich die einzelnen Textboxen vor dem
    Schließen des Formular wieder auslesen und an das
    Ursprungsformular zurückgeben.

    Du musst nur Dein DataGridView und Deine Textboxen an die
    selbe Datenquelle (DataTable/DataView oder Bindingsource)
    binden.

    Hier ein Beispiel:
    Erstelle ein neues Projekt mit einer leeren Form1 (Form1.vb)
    und einer leeren Form2 (Form2.vb). Kopiere nachfolgenden
    Code in die Formmodule Form1.vb bzw. Form2.vb

    ' / Code in Form1.vb
    Public Class Form1
        Private WithEvents DGV As DataGridView
        Private mDT As DataTable
        Private WithEvents mBS As BindingSource

        Private Sub Form1_Load _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles Me.Load

            DGV = New DataGridView
            With DGV
                .Dock = DockStyle.Fill

                .DefaultCellStyle.Font = _
                        New Font("Arial", 12)

                .ColumnHeadersDefaultCellStyle.Font = _
                        New Font("Arial", 8, FontStyle.Bold)

            End With
            Me.Controls.Add(DGV)

            CreateData()

            With DGV
                .DataSource = mBS

                .Columns(0).DefaultCellStyle.Alignment = _
                        DataGridViewContentAlignment.MiddleRight

                .AutoResizeColumns()

                .AllowUserToAddRows = False
                .ReadOnly = True
            End With

            Me.Height = 400

        End Sub

        Private Sub CreateData()
            Dim i As Integer
            Dim DR As DataRow

            mDT = New DataTable
            With mDT
                .Columns.Add("ID", GetType(Integer))
                .Columns.Add("SText", GetType(String))
                .Columns.Add("LText", GetType(String))

                For i = 1 To 12
                    DR = .NewRow
                    DR.Item(0) = i
                    DR.Item(1) = MonthName(i, True)
                    DR.Item(2) = MonthName(i, False)
                    .Rows.Add(DR)
                Next
                .AcceptChanges()
            End With

            mBS = New BindingSource
            mBS.DataSource = mDT
        End Sub

        Private Sub Form1_Shown _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles Me.Shown

            Form2.Show(Me)
            Form2.BS = mBS
        End Sub

        Private Sub mBS_ListChanged _
                (ByVal sender As Object, _
                 ByVal e As System.ComponentModel.ListChangedEventArgs _
                 ) Handles mBS.ListChanged

            If e.ListChangedType = System.ComponentModel.ListChangedType.ItemAdded Then
                DGV.Refresh()
            End If
        End Sub

    End Class
    ' \\\ Ende Form1.vb
    ' ##############

    ' ##############
    ' / Code in Form2.vb
    Public Class Form2
        Private WithEvents txtID As TextBox
        Private WithEvents txtLText As TextBox
        Private WithEvents mOF As Form1
        Private WithEvents mBS As BindingSource

        Friend Property BS() As BindingSource
            Get
                Return mBS
            End Get
            Set(ByVal value As BindingSource)
                mBS = value
            End Set
        End Property

        Private Sub Form2_Load _
                (ByVal sender As System.Object, _
                 ByVal e As System.EventArgs _
                ) Handles MyBase.Load

            mOF = DirectCast(Me.Owner, Form1)

            CreateControls()
        End Sub

        Private Sub NavButton_Click _
                (ByVal sender As System.Object, _
                 ByVal e As System.EventArgs)

            txtLText.Focus()
            Select Case DirectCast(sender, Button).Name
                Case "btnFirst"
                    mBS.Position = 0
                Case "btnPrevious"
                    mBS.Position -= 1
                Case "btnNext"
                    mBS.Position += 1
                Case "btnLast"
                    mBS.Position = mBS.Count - 1
                Case "btnNew"
                    mBS.AddNew()
                    txtID.Focus()
            End Select
        End Sub

        Private Sub CreateControls()
            Dim i As Integer
            Dim BtnNames() As String
            Dim BtnText() As String

            txtID = New TextBox
            With txtID
                .Name = "txtID"
                .Font = New Font("Arial", 14)
                .SetBounds(10, 15, 50, .Height)
            End With
            Me.Controls.Add(txtID)

            txtLText = New TextBox
            With txtLText
                .Name = "txtLText"
                .Font = txtID.Font

                .SetBounds _
                    (txtID.Right + 3, txtID.Top, _
                     180, .Height)

            End With
            Me.Controls.Add(txtLText)

            Me.ClientSize = _
                    New Size _
                        (txtLText.Right + 10, _
                         txtLText.Bottom + 75)

            txtLText.Anchor = _
                    AnchorStyles.Left Or _
                    AnchorStyles.Top Or _
                    AnchorStyles.Right

            BtnNames = _
                New String() _
                {"btnFirst", "btnPrevious", "btnNext", "btnLast", "btnNew"}

            BtnText = New String() {"|<", "<", ">", ">|", ">||"}

            Dim Left As Integer = txtID.Left
            Dim Top As Integer = txtLText.Bottom + 20
            Dim Btn As Button

            For i = 0 To BtnNames.GetUpperBound(0)
                Btn = New Button
                With Btn
                    .Name = BtnNames(i)
                    .Font = New Font("Arial", 12, FontStyle.Bold)
                    .Text = BtnText(i)
                    .SetBounds(Left, Top, 40, 40)
                End With
                Me.Controls.Add(Btn)
                AddHandler Btn.Click, AddressOf NavButton_Click
                Left = Btn.Right + 2
            Next

        End Sub

        Private Sub BindControls()
            Dim B As Binding

            B = New Binding _
                    ("Text", mBS, "ID", True, _
                     DataSourceUpdateMode.OnPropertyChanged)

            DirectCast _
                    (Me.Controls("txtID"),  _
                    TextBox).DataBindings.Add(B)

            B = New Binding _
                    ("Text", mBS, "LText", True, _
                     DataSourceUpdateMode.OnPropertyChanged)

            DirectCast _
                    (Me.Controls("txtLText"),  _
                    TextBox).DataBindings.Add(B)

        End Sub

        Private Sub Form2_Shown _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles Me.Shown

            Dim F As Form = Me.Owner

            Me.Width = F.Width
            Me.Location = New Point(F.Left, F.Bottom)
            BindControls()
        End Sub

        Private Sub mOF_LocationChanged _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles mOF.LocationChanged

            Me.Location = New Point(mOF.Left, mOF.Bottom)
        End Sub

        Private Sub txtID_TextChanged _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles txtID.TextChanged

            Dim DRV As DataRowView = _
                    DirectCast(mBS.Current, DataRowView)

            If DRV.IsEdit Then
                Dim Value As Integer
                If Integer.TryParse(txtID.Text, Value) Then
                    DRV.Row.Item(0) = Value
                Else
                    DRV.Row.Item(0) = DBNull.Value
                End If
            End If
            mBS.EndEdit()
        End Sub

        Private Sub txtLText_TextChanged _
                (ByVal sender As Object, _
                 ByVal e As System.EventArgs _
                ) Handles txtLText.TextChanged

            Dim DRV As DataRowView = _
                    DirectCast(mBS.Current, DataRowView)

            If DRV.IsEdit Then
                DRV.Row.Item(2) = txtLText.Text
            End If
            mBS.EndEdit()
        End Sub

    End Class
    ' \\\ Ende Form2.vb

    Nach dem Programmstart siehst Du Form1 mit dem DGV
    und Form2 mit den Textboxen und Buttons zum Navigieren
    im Datenbestand.

    Die Dateneingabe erfolgt in den Textboxen der Form2.
    Jede Eingabe wird zeitgleich im DGV der Form1 sichtbar.

    Gruß aus St.Georgen
    Peter Götz
    www.gssg.de (mit VB-Tipps u. Beispielprogrammen)

    Donnerstag, 23. September 2010 17:46
  • Hallo zusammen,

    nachdem ich mir eure Beispiele etwas näher angeschaut hatte, war klar was fehlte. "Einfach" abschließend beim DataGridView die Methode Refresh() aufrufen, und schon klappts auch mit der richtigen Anzeige eines neuen Datensatzes im DGV :-)

    Vielen, vielen Dank nochmals. Ihr habt mir sehr weitergeholfen!

    Grüße,

    Martin

    Freitag, 24. September 2010 05:09