question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

DataGridView bound to dataset's related grandchild with no records raises System.InvalidOperationException

See original GitHub issue
  • .NET Core Version: 5

  • Have you experienced this same bug with .NET Framework?: Yes

Problem description:

Dataset with 3 tables: Parent, Child, Grandchild, and 2 DataRelations: Child->Parent, Grandchild->Child. DataGridView added to form. Setting the DataGridView’s DataSource to the Parent and DataMember to Grandchild results in: System.InvalidOperationException: ‘Item cannot be added to a read-only or fixed-size list.’

System.InvalidOperationException
  HResult=0x80131509
  Message=Item cannot be added to a read-only or fixed-size list.
  Source=System.Windows.Forms
  StackTrace:
   at System.Windows.Forms.BindingSource.AddNew()
   at System.Windows.Forms.CurrencyManager.AddNew()
   at System.Windows.Forms.RelatedCurrencyManager.ParentManager_CurrentItemChanged(Object sender, EventArgs e)
   at System.Windows.Forms.RelatedCurrencyManager.Bind(BindingManagerBase parentManager, String dataField)
   at System.Windows.Forms.BindingContext.EnsureListManager(Object dataSource, String dataMember)
   at System.Windows.Forms.DataGridView.DataGridViewDataConnection.SetDataConnection(Object dataSource, String dataMember)
   at System.Windows.Forms.DataGridView.set_DataMember(String value)
   at Deleteme.Form1.Form1_Load(Object sender, EventArgs e) in C:\...\Form1.vb:line 26
   at System.Windows.Forms.Form.OnLoad(EventArgs e)
   at System.Windows.Forms.Form.OnCreateControl()
   at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   at System.Windows.Forms.Control.CreateControl()
   at System.Windows.Forms.Control.WmShowWindow(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   at System.Windows.Forms.ContainerControl.WndProc(Message& m)
   at System.Windows.Forms.Form.WmShowWindow(Message& m)
   at System.Windows.Forms.Form.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, WM msg, IntPtr wparam, IntPtr lparam)

  This exception was originally thrown at this call stack:
    System.Windows.Forms.BindingSource.AddNew()
    System.Windows.Forms.CurrencyManager.AddNew()
    System.Windows.Forms.RelatedCurrencyManager.ParentManager_CurrentItemChanged(object, System.EventArgs)
    System.Windows.Forms.RelatedCurrencyManager.Bind(System.Windows.Forms.BindingManagerBase, string)
    System.Windows.Forms.BindingContext.EnsureListManager(object, string)
    System.Windows.Forms.DataGridView.DataGridViewDataConnection.SetDataConnection(object, string)
    System.Windows.Forms.DataGridView.DataMember.set(string)
    Deleteme.Form1.Form1_Load(Object, System.EventArgs) in Form1.vb
    System.Windows.Forms.Form.OnLoad(System.EventArgs)
    System.Windows.Forms.Form.OnCreateControl()
    ...
    [Call Stack Truncated]

If Parent has a record, and only Child and Grandchild not, there is no error. The error is specifically when there are three generations. (The example below is part of a larger example, with more details in a comment.)

Expected behavior:

No error.

Minimal repro:

New vb winforms project, replace Form1 with:

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim Data As New DataSet
        Dim Dgv As New DataGridView

        Controls.Add(Dgv)

        Data.Tables.Add(New DataTable("Parent"))
        Data.Tables("Parent").Columns.Add("Id")

        Data.Tables.Add(New DataTable("Child"))
        Data.Tables("Child").Columns.Add("Id")

        Data.Tables.Add(New DataTable("Grandchild"))
        Data.Tables("GrandChild").Columns.Add("Id")

        ' Uncomment for no error.
        'Data.Tables("Parent").Rows.Add(1)

        Data.Relations.Add(New DataRelation("Parent_Child", Data.Tables("Parent").Columns("Id"), Data.Tables("Child").Columns("Id")))
        Data.Relations.Add(New DataRelation("Child_Grandchild", Data.Tables("Child").Columns("Id"), Data.Tables("Grandchild").Columns("Id")))

        Dgv.DataSource = New BindingSource With {.DataSource = Data, .DataMember = "Parent"}
        Dgv.DataMember = "Parent_Child.Child_Grandchild"

    End Sub

End Class

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:36 (22 by maintainers)

github_iconTop GitHub Comments

1reaction
weltkantecommented, Feb 10, 2021

How do i connect all three when using the new datasource?

By doing it the same way you are doing it currently, by sharing the data source. Each data source (be it implicitly generated or explicitly) has a “current” record. Thats why I said earlier

Personally I’d recommend orienting yourself on designer generated code rather than generating disposable objects ad hoc and then forgetting about them.

Binding sources are “components” which are similar to controls, they are supposed to be shared, not objects you construct to pass data and then throw away. Technically you are even supposed to keep them arround and dispose them later (I don’t know if it has any ill effect not doing so, assuming the form doesn’t outlive the grids I’d expect the garbage collector to clean up after you.)

var bs1 = new BindingSource() { DataSource = Data, DataMember = "Parent" };
var bs2 = new BindingSource() { DataSource = bs1, DataMember = "Parent_Child" };
// you could do a bs3 instead of setting the DataMember on the Dgv3, which is useful in case the selection on Dgv3 is supposed to affect another details area (e.g. databound textboxes)

Dgv1.DataSource = bs1;
Dgv2.DataSource = bs2;
Dgv3.DataSource = bs2;
Dgv3.DataMember = "Child_Grandchild";

Does this achieve what you are looking for or am I still missing some detail? Clicking a row in any grid seems to change the dependent grids appropriately as expected for binding sources.

1reaction
chacham2commented, Feb 4, 2021

Applied the workaround applied and was able to run the code. Thank you for all the help in getting thus far!

Untitled

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - System.InvalidOperationException: rows cannot be ...
System.InvalidOperationException: rows cannot be programmatically added to the datagridview's rows collection when the control is data-bound.
Read more >
How to bind three datagridviews together as parent, child ...
I want to click on a record in parent and have the related records show up in child, and then child's related records...
Read more >
Access Objects Bound to DataGridView Rows
Learn how to access objects bound to Windows Forms DataGridView rows to display a table of information stored in a collection of business ......
Read more >
DataGridView.DataBindingComplete Event
This event is raised when the contents of the data source change or when the value of the DataSource, DataMember, or BindingContext property...
Read more >
[Solved] How can I add rows to a datagridview while ...
"System.InvalidOperationException: 'Rows cannot be programmatically added to the DataGridView's rows collection when the control is data-bound."
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found