1

I have 3 different datagridviews all bound to a separate bindingsource. I would like to update the datagridviews when new data is loaded into the bindingsources. I have tried the generally accepted method for solving this problem here:

1.) Create a Binding Source

2.) Set the Datasource for this object to your Dataset Table.

3.) Set The datasource for your DatagridView as the Binding source Object.

bindingsrc.DataSource = newDataTable;

// The two lines below were supposedly a dirty solution to refreshing the grid.

dg1.DataSource = null;
dg1.DataSource = bindingsrc;

However it doesn't work. I have also tried to reset the bindings for each bindingsource:

bindingsrc.ResetBindings();

but to no avail. I know I am getting the correct new data, because once I step into the code when debugging, newDataTable has the correct new data. So it is a matter of the datagridview not refreshing. In case this might be relevant, my datagridviews are part of a panel whose parent is a splitcontainer. I have also tried to refresh the parent:

this.dataGridView.Parent.Refresh()

without any results.

Iason
  • 209
  • 3
  • 11
  • 38
  • Try "dg1.Refresh();" – Paul Weiland Dec 14 '15 at 13:26
  • I can't see a function named like that. – Iason Dec 14 '15 at 13:28
  • Did try this as well, to no avail unfortunately. – Iason Dec 14 '15 at 13:32
  • Could you try refreshing the DataGridView first and then refreshing the parent afterwards ? – Paul Weiland Dec 14 '15 at 13:36
  • The datagridview still doesn't get refreshed. – Iason Dec 14 '15 at 13:44
  • Would I possibly need to use a bindinglist? – Iason Dec 14 '15 at 14:29
  • If you are using `DataTable` and `BindingSource` no you don't need to use `BindingList`. Can you reproduce the problem whit a minimal code sample? Main benefit of writing such minimal code to reproduce the problem is it increases your chance to find the problem while writing such minimal code, and if you don't find the problem yourself, having such reproduction code, other users can share their idea about the problem. If you couldn't reproduce the problem, so other users probably can not help you. – Reza Aghaei Dec 14 '15 at 14:36
  • I am using a DataTable yes. Basically the constructor sets up a few variables, and asynchronously calls GetData(). This function gets all my data, and at the end again asynchronously calls UpdateDataGrids(DataTable mytable). Having debugged up to here, the values inside mytable are the correct new values. – Iason Dec 14 '15 at 14:42
  • Then I simply do bindingSource1.DataSource = mytable; bindingSource2.DataSource = mytable; bindingSource3.DataSource = mytable; dataGridView1.DataSource = bindingSource1; dataGridView2.DataSource = bindingSource2; dataGridView3.DataSource = bindingSource3; This code goes inside my UpdateDataGrids function. – Iason Dec 14 '15 at 14:42
  • Do your grid have columns? Do you see previous data? What's the result in the grid? – Reza Aghaei Dec 14 '15 at 14:44
  • The datatable has 35 columns at the start, so does my datagridview. When I try to load another datatable of 2 columns though, the change isn't reflected. Edit: The datagridview doesn't have any columns at design time, if that's what you were asking. It just loads up the datatable. – Iason Dec 14 '15 at 14:46
  • Probably you need to try this code: this.dataGridView1.AutoGenerateColumns = true;this.dataGridView1.DataSource = this.otherBindingSource; Let me know the result. – Reza Aghaei Dec 14 '15 at 15:05
  • I tried this in the UpdatedataGrids function. No change. – Iason Dec 14 '15 at 15:06
  • There is one very similar question to mine, and the answer suggests handling the appropriate event for the binding source initialization. http://stackoverflow.com/questions/5303992/cant-refresh-datagridview-with-bindingsource?rq=1 Does this mean handling the BindingContext_Changed event? I don't have a static constructor however. – Iason Dec 14 '15 at 15:11
  • To receive more effective helps maybe it's better to share a simple code to reproduce the problem. By the way, when answering a comment you can use @ to inform the user :) – Reza Aghaei Dec 14 '15 at 15:51
  • @RezaAghaei I found the solution to my particular problem. Do you think calling Dispose is prudent? – Iason Dec 15 '15 at 08:43
  • To be honest I have no idea about why and where and what the object may need `.Dispose()` – Reza Aghaei Dec 15 '15 at 09:30
  • @RezaAghaei From my original question: "In case this might be relevant, my datagridviews are part of a panel whose parent is a splitcontainer." So the line of code: split.Panel2.Controls.Add(new ConfigurableMatrices(comboBox1.SelectedItem.ToString(), comboBox2.SelectedItem.ToString())); was re-adding this class with all its controls to the second panel of the splitcontainer parent. This line of code is executed from the other half of the splitcontainer. – Iason Dec 15 '15 at 09:55

2 Answers2

1

I found the solution to my problem. I did not need to handle the BindingContext_Changed event, and the general methodology of:

bindingSource1.ResetBindings(false);
dataGridView1.DataSource = null;
bindingSource1.DataSource = null;
bindingSource1.DataSource = mytable;
dataGridView1.DataSource = bindingSource1;

was the correct way to update the grid.

The real problem: From my original question: "In case this might be relevant, my datagridviews are part of a panel whose parent is a splitcontainer." The following line of code:

 split.Panel2.Controls.Add(new ConfigurableMatrices(comboBox1.SelectedItem.ToString(), comboBox2.SelectedItem.ToString())); 

was re-adding this class (ConfigurableMatrices, which is the one which has my datagridviews in it) with all its controls to the second panel of the splitcontainer parent. This line of code is executed from the other half of the splitcontainer. I was also refreshing after that:

split.Panel2.Controls.Add(new ConfigurableMatrices(comboBox1.SelectedItem.ToString(),  
comboBox2.SelectedItem.ToString()));
split.Panel2.Refresh();

However this way, I was only adding a new class (ConfigurableMatrices) each time on top, and this didn't for some reason correctly update. The solution which works for me right now is to call the Dispose method just before the above two lines of code:

foreach (Control control in split.Panel2.Controls)
        {
            control.Dispose();
        }
split.Panel2.Controls.Add(new ConfigurableMatrices(comboBox1.SelectedItem.ToString(), comboBox2.SelectedItem.ToString()));
split.Panel2.Refresh();

I'm hoping the Dispose method is the correct way to tackle this and won't trigger other problems in the future.

Iason
  • 209
  • 3
  • 11
  • 38
  • `dataGridView1.DataSource = null;` Did the trick for me, I added this just above where it was being set. – ILLEST Dec 12 '21 at 23:02
0

Under normal circumstances no refresh is needed. The following opens a Microsoft NorthWind database, loads all table names into a ComboBox with DropDownStyle = DropDownList. Select a table name in the ComboBox, press the button and our DataGridView is then loaded. I bypassed using a DataSet but that will not make a difference other then DataMember property of the DataGridView which if not set could cause the issue at hand so best to check Datamember is correct.

Code to get table names and give us our connection string no matter .accdb or .mdb

In this code we use SELECT * but of course in a real app we alone select the fields needed for a specific operation unless there is a need to see all fields.

Imports System.Data.OleDb
Public Class SchemaInfo
    Private Shared _Instance As SchemaInfo
    Public Shared Function GetInstance() As SchemaInfo
        If _Instance Is Nothing Then
            _Instance = New SchemaInfo
        End If
        Return _Instance
    End Function
    Protected Sub New()
    End Sub
    Private Shared _ConnectionString As String
    Public Function ConnectionString() As String
        Return _ConnectionString
    End Function
    Public Function TableNames(ByVal DatabaseName As String) As List(Of String)
        Dim Names As New List(Of String)

        Using cn As New OleDbConnection(BuildConnectionString(DatabaseName))
            _ConnectionString = cn.ConnectionString
            cn.Open()

            Dim dt As DataTable = cn.GetSchema("Tables", New String() {Nothing, Nothing, Nothing, "Table"})

            For Each row As DataRow In dt.Rows
                Names.Add(row.Field(Of String)("Table_Name"))
            Next

        End Using

        Return Names

    End Function
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Shared Function BuildConnectionString(ByVal DatabaseName As String) As String

        If IO.Path.GetExtension(DatabaseName).ToLower = ".accdb" Then

            Dim Builder As New OleDb.OleDbConnectionStringBuilder With
                {
                    .Provider = "Microsoft.ACE.OLEDB.12.0",
                    .DataSource = DatabaseName
                }

            Return Builder.ConnectionString

        ElseIf IO.Path.GetExtension(DatabaseName).ToLower = ".mdb" Then

            Dim Builder As New OleDb.OleDbConnectionStringBuilder With
                {
                    .Provider = "Microsoft.Jet.OLEDB.4.0",
                    .DataSource = DatabaseName
                }

            Return Builder.ConnectionString

        Else

            Throw New Exception("File type not supported")

        End If

    End Function
End Class

Form code

Imports System.Data.OleDb

Public Class SwitchTableOnBindingSourceForm
    WithEvents bsData As New BindingSource
    Private Sub SwitchTableOnBindingSourceForm_Load(
        sender As Object, e As EventArgs) Handles MyBase.Load

        cboTables.DataSource = SchemaInfo.GetInstance.TableNames(
            IO.Path.Combine(
                AppDomain.CurrentDomain.BaseDirectory, "NorthWind.accdb"))

        DataGridView1.DataSource = bsData

    End Sub
    Private Sub cmdSelectTable_Click(
        sender As Object, e As EventArgs) Handles cmdSelectTable.Click

        Dim dt As New DataTable
        Using cn As New OleDbConnection(SchemaInfo.GetInstance.ConnectionString)
            Using cmd As New OleDbCommand("SELECT * FROM " & cboTables.Text, cn)
                cn.Open()
                dt.Load(cmd.ExecuteReader)
            End Using
        End Using

        bsData.DataSource = dt

    End Sub
End Class
Karen Payne
  • 4,341
  • 2
  • 14
  • 31