Home > Net >  Problem accessing DatagridView from another form (child)
Problem accessing DatagridView from another form (child)

Time:12-22

I have a datagridView on Form1. When I double-click on an item in that Datagridview, I go to a detailform where I get to see the details of the line in the datagridview. (I get them based on the id of the record I keep in the datagridview). Now I want to make prev/next buttons on the detailform so that the user doesn't have to go back to form1.

I can access the datagridview (which is public), but I can't see the row info.

In the debugger I can see the row info if I start from this.Owner.Controls[0].Controls[2].Controls[0] and then click to open the Rows properties. When I enter this.Owner.Controls[0].Controls[2].Controls[0].Rows[0], I get error CS1061.

How can I fix this?

CodePudding user response:

This is a data type issue. Looking at this expression:

this.Owner.Controls[0].Controls[2].Controls[0].Rows[0]

We can follow the data type of each part of the expression from beginning to end to see the problem.

First, the type of this is the current Form, which will be something inherited from System.Windows.Forms.Form. From there, we check that type's .Owner property, and see it also a (nullable) System.Windows.Forms.Form.

Now we start looking at the Form type's .Controls member. We find the datatype here by understanding that Form inherits from System.Windows.Forms.Control, which leads us to the property definition. Now we learn we're looking at a System.Windows.Forms.ControlCollection. This type has an indexer property that allows you to make the [0] and [2] lookups (probably better to do this by name, fwiw). The documentation for this property tells us the result of the indexer expression is back to System.Windows.Forms.Control.

Now we know enough to understand that when we take this expression:

this.Owner.Controls[0].Controls[2].Controls[0]

the data type chain for the expression looks like this:

this   .Owner .Conrols            [0]       .Controls           [2]       .Controls           [0]
Form > Form > ControlCollection > Control > ControlCollection > Control > ControlCollection > Control

It shows the final result is a System.Windows.Forms.Control. From there we go look for the .Rows property and find... nothing. The basic Control type does not provide this property.

So why does it work in the debugger? At run time, we aren't dealing with base Control objects. We are dealing with types that inherit from Control, like Panel, TextBox, or DataGridView. It just so happens the DataGridView control does provide a Rows property. The debugger allows you to resolve this to use the run time type, but the compiler doesn't know what's going to happen once the program starts running; it has to be more strict. For example, you might have a button to remove the gridview and put something else there instead, and now the Rows expression would no longer be valid.

You can smooth over the compiler issue with a cast:

var dgv = (DataGridView)this.Owner.Controls[0].Controls[2].Controls[0];
var row = dgv.Rows[0];

But this is tightly-coupled to the form layout. Move something around in the designer and suddenly you're tracing through a lot of code to find out what went wrong. You will be better off setting a reference directly to the DataGridView in the child form before even showing it on the screen.

var child = new detailForm(this);
child.ParentGrid = this.DataGridView1; // assuming you declare a public property named "ParentGrid" and your control is named DataGridView1
child.ShowDialog();

Finally, you may be wondering whether you're expected to work through a data type expression chain like that for every line of code you use. I'd say you are expected to understand what data types you're working with at every level of every expression. Fortunately, this doesn't mean you need to have it all memorized. It doesn't take much experience to understand how the Windows Forms types fit together generally, so you can understand these data types without having to go chase through the documentation on every single thing. And speaking of "chasing through the documentation. When you really don't know, you are expected to know how to read the docs to find the answer.

CodePudding user response:

Assuming this is a read-only operation, I would pass the DataGridView to the detail form. You could create a constructor for the detail form that takes a DataGridView as a parameter, or create some kind of public void Populate(DataGridView dgv) { } function that you call after the form constructor.

If you intend on changing data in the DataGridView from the detail page, and expect it to reflect on the main form, then you can either create a event on the detail form that the main form listens for, or after the detail form closes, retrieve the stored DataGridView and look for changes (or just overwrite).

  •  Tags:  
  • c#
  • Related