Alex
Alex

Reputation: 828

c# datagrid view leaves previous rows blank

I'm currently trying to input information into a data grid view, but when I try to do it, if the user has got a cell selected that one won't have a value afterwards, and i fixed this using a refreshedit(); at the end of the loop, however that meant that only the last row was written to at the end

here's the code at the moment

        foreach ( Contact c in currentBook.Contacts )
        {

            ContactsList.RowCount = i + 1;
            ContactsList.Rows[ i ].Cells[ 1 ].Value = c.FirstName;
            ContactsList.Rows[ i ].Cells[ 2 ].Value = c.Surname;
            ContactsList.Rows[ i ].Cells[ 3 ].Value = c.Address;
            ContactsList.Rows[ i ].Cells[ 4 ].Value = c.Town;
            ContactsList.Rows[ i ].Cells[ 5 ].Value = c.County;
            ContactsList.Rows[ i ].Cells[ 6 ].Value = c.Postcode;
            ContactsList.Rows[ i ].Cells[ 7 ].Value = c.PhoneNum;
            ContactsList.Rows[ i ].Cells[ 8 ].Value = c.Email;
            i++;

        }

this code gets an exception saying: Operation did not succeed because the program cannot commit or quit a cell value change.

so i added in a

ContactsList.RefreshEdit();

after incrementing i however this means only the last row is displayed

I'll be grateful for any help

thanks

Upvotes: 1

Views: 1537

Answers (2)

Matt
Matt

Reputation: 27001

Alex, you are using an unbound DataGridView as I can see from your code and I was able to reproduce the issue and solve it:

DataGridView example

The DataGridView in this example has already three columns, added through the Visual Studio designer (right-click on the triangle of the DataGridView and subsequently add 3 columns to it as in the screenshot above shown). This is a prerequisite for the example below.

Take a look at this code (I've taken out some of the address fields to make it shorter and the DataGridView is named dgvContactsList to distinguish it from the list contactsList):

    private void RefreshDgvContacts()
    {
        if (contactsList.Count > dgvContactsList.Rows.Count)
            dgvContactsList.Rows.Add(
                contactsList.Count - dgvContactsList.Rows.Count
            );
        int i = 0;
        foreach (Contact c in contactsList)
        {
            dgvContactsList.Rows[i].Cells[0].Value = c.Firstname;
            dgvContactsList.Rows[i].Cells[1].Value = c.Surname;
            dgvContactsList.Rows[i].Cells[2].Value = c.Address;
            i++;
        }
    }

Call this method in the following events:

    private void btnRefresh_Click(object sender, EventArgs e)
    {
        RefreshDgvContacts();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        RefreshDgvContacts();
    }

Note that contactsList is in my example defined as follows (it is declared within the form class containing the DataGridView):

    public List<Contact> contactsList = new List<Contact>()
    {   new Contact() {Firstname="Mark", Surname="Hamill", 
                       Address="Hollywood"},
        new Contact() {Firstname="Harrison", Surname="Ford", 
                       Address="Hollywood"}
    };
public class Contact
{
    [DataObjectField(false)]
    public string Firstname { get; set; }

    [DataObjectField(false)]
    public string Surname { get; set; }

    [DataObjectField(false)]
    public string Address { get; set; }
}

What is important in the example is that you create all the rows as needed before you change the values. Note that you can call the method RefreshDgvContact multiple times (e.g. from a refresh button) and it still works, because rows are only added if they don't exist already.

Also important to mention is that if you're filling a DataGridView as shown here, it cannot be bound to a datasource at the same time. If you intended to bind the datasource, take a look at the other example already posted by David.

However, I think it is important to have both examples because sometimes it is useful to not bind a datasource, sometimes a bound datasource is more handy.


For those of you who want to reproduce the issue, you can replace the working RefreshDgvContacts method by the following method (don't forget to change the events Form1_Load() and btnRefresh_Click() too):

    private void RefreshDgvContacts_WithIssue()
    {   // this sample leaves the 1st row blank called in Form1_Load
        // 2nd and subsequent calls, e.g. from the Refresh button don't show
        // the issue.
        int i = 0;
        foreach (Contact c in contactsList)
        {
            if (i >= dgvContactsList.Rows.Count)
                dgvContactsList.Rows.Add();
            dgvContactsList.Rows[i].Cells[0].Value = c.Firstname;
            dgvContactsList.Rows[i].Cells[1].Value = c.Surname;
            dgvContactsList.Rows[i].Cells[2].Value = c.Address;
            i++;
        }
    }

It is surprising to see that the position of the dgvContactsList.Rows.Add() is important, isn't it? With this code, the form loads as follows:

Example showing issue

Note that clicking the Refresh button works fine even with the method RefreshDgvContacts_WithIssue().

But now we've learned that we better use the first example, i.e. RefreshDgvContacts() to load the DataGridView.

Upvotes: 1

David Hall
David Hall

Reputation: 33143

The easiest way to get data into a DataGridView is to use a DataSource and then add your data to that DataSource.

The exact details depend a lot on what you are trying to do - there are lots of different approachs, but below is a simple example using a BindingSource as the datasource for the grid.

BindingSource bs = new BindingSource();  

public Form1()
{
    InitializeComponent();

    dataGridView1.DataSource = bs; 
}

Then when you want to add your new contacts:

foreach (Contact c in currentBook.Contacts)
{
    bs.Add(c);
}

You should generally be able to bind currentBook.Contacts directly to the grid as the DataSource but it isn't entirely clear if that will work in your situation.

Read up on databinding and the DataGridView for more information. This MSDN article is a good place to start: DataGridView Control Overview

Upvotes: 0

Related Questions