3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C# - DataGridViewのDataSourceをAllowUserToAddRows=trueで運用するとプログラムからデータを追加できなくなる?

Posted at

DataGridViewのDataSourceをAllowUserToAddRows=trueで運用するときの振る舞い

DataGridView は、AllowUserToAddRows=true(※このプロパティはデフォルトでtrueになっている)で運用すると、BindingSourceで紐づけている内部データの末尾要素に、ユーザー編集用の1行分のデータ(以下「仮のデータ」と呼ぶことにする)を勝手に追加したり取り消し削除したりと、やりたい放題してくれちゃう仕様のようです。

そのため、BindingSourceAddメソッドで追加すると、「仮のデータ」の後ろにデータが追加されるため、内部的に要素数の不整合が発生するようです。

対策

ユーザーによる直接入力での行追加をさせないのであれば、AllowUserToAddRows=falseで使うのが一番手っ取り早い。
AllowUserToAddRows=trueで運用したいなら、以下のように、「仮のデータ」があるかどうかによって、挿入するインデックスを調整すれば、正しく追加できるようである。

ソースコード


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;

    // DataGridViewに表示する項目
    public class ExampleItem
    {
        // フィールドは表示されない。プロパティにする必要がある。
        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 ) { // 対策コード
                wrapper.Insert(items.Count-1, item);                   // 対策コード
            }                                                          // 対策コード
            else {                                                     // 対策コード
                wrapper.Add(item);
            }                                                          // 対策コード
            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));
    }
}

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?