Yoki
Yoki

Reputation: 1

How to autofill form when i click data in DataGridView in Windows Forms

I want to make the form text boxes get filled automatically when I click data in the DataGridView given in my form.

The Form IMG

I want the Dynamic Textboxes to get filled automatically, i.e. I want to pass the data from DataGridView to the active textboxes I just do not know how to do it. Didnt find anything on the internet that helps, or I probably didnt phrase it right. Any solution is okay, and i dont need the whole code, just the concept of it, or some pseudo code will do. P.S. I used an MS Access database for this.

Upvotes: -1

Views: 110

Answers (2)

Harald Coppoolse
Harald Coppoolse

Reputation: 30502

Ok, so you have a collection of Persons, where each Person has several properties. You also have a DataGridView that shows the Id and the UserName of the Persons in your collection.

Whenever the operator clicks one of the rows of the DataGridView, you want to show the values of the other properties of the Person in text boxes.

Separation of data and the way that it is displayed

Quite often when using a DataGridView people tend to fiddle with the contents of rows and columns and cells directly.

For several years already, there is a tendency to separate Data (=Model) from how it is displayed (=View). The major advantage of this, is that you can change your View, without having to change the Model. You can also change the Model without having to change the way that it is displayed.

For example, if you have a list of Sales, where every Sale has a Date and a Total amount of sales on that date, you can show this list in a table / DataGridView, but you can also decide to show this in a Chart, without having to change your list of sales.

On the other hand, if in the future you want to change the list to a database, the separation of Model and View ensures that you don't have to change the View for this.

To connect the Model, with the View, an adapter class is needed, called the ViewModel. Together these three classes are abbreviated as MVVM. If you are not familiar with this concept, consider to read some background information about MVVM.

Your DataGridView and MVVM

So you have a collection of Persons. Class Person will be something like this:

class Person
{
    public int Id {get; set;}
    public string UserName {get; set;}
    public string FirstName {get; set;}
    ...
}

Your form has methods te retrieve the collection of Persons that must be displayed:

public IEnumerable<Person> GetPersonsToDisplay() {...};

I'll leave the implementation to you. After all you know where you get your Persons: from a text file, a database, or maybe from the internet.

In the windows designer, you have added the DataGridView and your columns to the form. This is done using property DataGridViewColumn.DataPropertyName You can also use the designer to specify the value of this property. I prefer to do this in the constructor of the Form.

public MyForm()
{
    InitializeComponents();

    // define which property is shown in which column:
    this.ColumnId.DataPropertyName = nameof(Person.Id);
    this.ColumnUserName.DataPropertyName = nameof(Person.UserName);
    ... // etc, if in future you want to show more Person properties in your DataGridView

The advantage of this method is, that your compiler will warn you if in future you decide to change the properties and you forgot to change the constructor.

To show your list of persons, one line of code is sufficient:

this.DgvPersons.DataSource = this.GetPersonsToDisplay.ToList();

And presto! All persons are shown in the DataGridView.

However, quite often people want to be able to edit the contents of the table. They want automatic updates after the operator indicates he has finished editing. This can also be done in only a few lines of code using a BindingList

public BindingList<Person> DisplayedPersons
{
    get => (BindingList<Person>)this.DgvPersons.DataSource;
    set => this.DgvPersons.DataSource = value;
}

Again, initializing the DataGridView is a one lines:

this.DisplayedPersons = new BindingList<Person>(this.GetPersonsToDisplay.ToList());

Now Suppose the operator has edited the table, and presses the Apply Now button to indicate that he has finished editing. Add an event handler for this button:

public void OnButtonApplyNow_Clicked(object sender, ...)
{
    ICollection<Person> editedPersons = this.DisplayedPersons;
    this.ProcessEditedPersons(editedPersons);
}

Method ProcessEditedPersons can compare the original Persons with the editedPersons, to find out the deleted Persons, the added Persons and the Persons that were changed, and act accordingly. The implemenation is out of scope of this question.

Finally two nice properties to have:

public Person CurrentPerson => (Person)this.DgvPersons.CurrentRow.DataBoundItem;
    
public IEnumerable<Person> SelectedPersons => this.DgvPersons.SelectedRows
    .Cast<DataGridViewRow>()
    .Select(row => row.DataBoundItem)
    .Cast<Person>();

By the way, I prefer not to convert everything to a List. First it would be quite a waste of processing power if you would only use the first few elements of a List. Furthermore, if you implement Sorting the DataGridView the order of the Persons that you get is not defined; Person[4] wouldn't have a meaningful defined meaning. If the caller of my properties need a Collection or a List, they can do the ToList.

The above described properties can be used for any datagridview. The model is completely separated from the view. The methods that I described are the ViewModel. For small forms, just add those methods to your Forms. If you want to be able to reuse them in other forms, consider to create a separate ViewModel class.

Back to your problem

Now that you have separated your model from your View, the display of the properties of the selected Person is simple:

void DisplayPerson(Person Person)
{
    this.TextBoxUserId.Text = person.Id.ToString();
    this.TextBoxUserFirstName.Text = sperson.FirstName;
    this.TexBoxLastName.Text = person.LastName;
    ...
}

All you have to do is add an event handler for DataGridView.CurrentCellChanged. Again, after all the work (after all these one line methods), this is a one liner:

public void OnPersonsTable_CurrentCellChanged(object sender, ...)
{
    this.DisplayPerson(this.SelectedPerson)
    // TODO: optimization if Person already is displayed
}

Note: this will also work if you step through your table using arrow keys, or page up / page down / Home / End. If you don't want this, subscribe to even CellClicked. Find out which Cell is clicked, find out the Row of this cell, and get the DataBoundItem:

public Person GetPerson(DataGridViewRow row)
{
    return (Person)row.DataBoundItem;
}

public void OnPersonsTable_CellClicked(object sender, DataGridViewCellEventArgs e)
{
    DataGridViewRow clickedRow = this.DgvPersons.Rows[e.RowIndex];
    Person clickedPerson = this.GetPerson(clickedRow);
    this.DisplayPerson(clickedPerson);
}

Of course if you want, you can do this in one line. The code won't be much more efficicient, however readability will deteriorate.

Summary

By separating your model from your view, you don't need to fiddle with cells and rows directly anymore.

By adding only a few properties, you can access the complete collection of Persons, the selected persons, or only the current Person. These properties are very small, using them is usually also with onlly a few lines of code.

Upvotes: 0

Yoki
Yoki

Reputation: 1

Okay so WinForms has a property in Design view, Events called CellContentClick and CellContentDoubleClick which invokes a certain event when called. So when i double click on a cell or element in the data after adding this code to the event :-

        {
            if (e.RowIndex != -1) 
            {
                DataGridViewRow row = dataGridViewUsers.Rows[e.RowIndex];
                //ID
                txtUsersUID.Text = row.Cells[0].Value.ToString();
                //Username
                txtUsersFirstname.Text = row.Cells[1].Value.ToString();
                //Password
                txtUsersPassword.Text = row.Cells[2].Value.ToString();
            }
        }

then it takes the value of the specified cells of the rows, for example :- Selected Cell of a DataGridView and then it passes the text to the specified Text Boxes :-

output of the code

Upvotes: 0

Related Questions