C # –If you operate DataGridView’s DataSource with AllowUserToAddRows = true, can’t you add data programmatically?

2 minute read

Behavior when operating DataGridView DataSource with AllowUserToAddRows = true

When DataGridView is operated with ʻAllowUserToAddRows = true` (* This property is true by default), one row of data for user editing (* this property is set to true by default) is added to the last element of the internal data linked by BindingSource. It seems to be a specification that allows you to do whatever you want, such as adding or canceling and deleting (hereinafter referred to as “temporary data”).

Therefore, if you add it with the ʻAdd method of BindingSource`, the data will be added after the “temporary data”, so it seems that an inconsistency in the number of elements will occur internally.

Countermeasures

If you don’t want users to add rows directly, it’s easiest to use ʻAllowUserToAddRows = false. If you want to operate with ʻAllowUserToAddRows = true, it seems that you can add it correctly by adjusting the index to be inserted depending on whether there is “temporary data” as follows.

Source code


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;


class MainForm : Form
{
    DataGridView dgv;
    BindingList<ExampleItem> items;
    BindingSource wrapper;

    //Items to display in DataGridView
    public class ExampleItem
    {
        //The field is not displayed. Must be a property.
        public string FileName {get;set;}
        
        public ExampleItem()
        {
            Console.WriteLine("ExampleItem() called.");
            FileName="xxx";
        }

        public static ExampleItem CreateItem(string fileName)
        {
            var item = new ExampleItem(){ FileName = fileName };
            Console.WriteLine(" by CreateItem.");
            return item;
        }
    }

    MainForm(string fileName)
    {
        items = new BindingList<ExampleItem>();

        Controls.Add(
            dgv = new DataGridView() {
                Dock = DockStyle.Fill,
                //AllowUserToAddRows = false,
                //AutoGenerateColumns = false,
                AllowDrop = true,
            }
        );
        wrapper = new BindingSource();
        wrapper.AddingNew       += (s,e)=>{Console.WriteLine("[BindingSource Event] AddingNew");};
        wrapper.BindingComplete += (s,e)=>{Console.WriteLine("[BindingSource Event] BindingComplete");};
        wrapper.DataSource = items;
        dgv.DataSource = wrapper;

        dgv.DragEnter += Control_DragEnter;
        dgv.DragDrop += Control_DragDrop;

        if ( fileName != null ) {
            RegisterItem(fileName);
        }
    }
    
    void Control_DragEnter(Object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent(DataFormats.FileDrop)) {
            e.Effect = DragDropEffects.Copy;
        }
        else {
            e.Effect = DragDropEffects.None;
        }
    }
    
    void Control_DragDrop(Object sender, DragEventArgs e)
    {
        Console.WriteLine("[Event] DragDrop");
        var fileNames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
        foreach ( var s in fileNames ) {
            RegisterItem(s);
        }
    }

    void RegisterItem(string filePath)
    {
        var item = ExampleItem.CreateItem(filePath);
        if ( item != null ) {

            Console.Write("DataGridView's Row Count: ");
            Console.WriteLine(dgv.Rows.Count);
            Console.Write("Internal data's Row Count: ");
            Console.WriteLine(items.Count);

            Console.WriteLine("Add...");
            if ( dgv.Rows.Count >= items.Count && items.Count >= 1 ) { //Countermeasure code
                wrapper.Insert(items.Count-1, item);                   //Countermeasure code
            }                                                          //Countermeasure code
            else {                                                     //Countermeasure code
                wrapper.Add(item);
            }                                                          //Countermeasure code
            Console.WriteLine("completed");

            Console.Write("DataGridView's Row Count: ");
            Console.WriteLine(dgv.Rows.Count);
            Console.Write("Internal data's Row Count: ");
            Console.WriteLine(items.Count);
        }
    }

    [STAThread]
    static void Main(string[] args)
    {
        Application.Run(new MainForm((args.Length==1)?args[0]:null));
    }
}