views:

936

answers:

2

I want an OpenFileDialog to come up when a user clicks on a cell, then display the result in the cell.

It all works, except that the DataGridView displays an extra row, for adding values to the list it's bound to. The row shows up if dataGridView.AllowUserToAddNewRows == true, which is what I want. What I don't want is for the application to crash when that row is edited programatically; instead, it should do exactly what it would do if the user had edited that row manually (add the new row to the underlying list, push another empty row onto the grid for adding values).

I read about SendKeys.Send(), which should make the DataGridView behave exactly as though the user had typed the value in; however, it does not work either. Here is what I am trying:

if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
    dataGridView1.CurrentCell = cell;

    //simply doing a cell.Value = etc. will cause the program to crash
    cell.ReadOnly = false;
    dataGridView1.Columns[cell.ColumnIndex].ReadOnly = false;
    dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
    dataGridView1.BeginEdit(true);
    SendKeys.Send(openFileDialog1.FileName + "{Enter}");
    dataGridView1.EndEdit();
    cell.ReadOnly = true;
    dataGridView1.Columns[cell.ColumnIndex].ReadOnly = true;
}
//I would expect the FileName would be in the cell now, and a new empty
//row tacked onto the end of the DataGridView, but it's not; the DataGridView
//is not changed at all.
+1  A: 

Try this:

        if (openFileDialog1.ShowDialog() == DialogResult.OK)
        {
            int row = e.RowIndex;
            int clmn = e.ColumnIndex;
            if(e.RowIndex == dataGridView1.Rows.Count- 1)
                dataGridView1.Rows.Add();
            dataGridView1.Rows[row].Cells[clmn].Value = openFileDialog1.FileName;
        }

EDIT I didn't notice that you are binding your datagridview :( Ok, to solve it: use binding source, set its DataSource property to your list, then set the data source of the data grid view to this binding source. Now, the code should look like so:

public partial class frmTestDataGridView : Form
    {
        BindingSource bindingSource1 = new BindingSource();
        List<string> datasource = new List<string>();
        public frmTestDataGridView()
        {
            InitializeComponent();
            datasource.Add("item1");
            datasource.Add("item2");
            datasource.Add("item3");

            bindingSource1.DataSource = datasource;
            dataGridView1.DataSource = bindingSource1;
        }

        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                int row = e.RowIndex;
                int clmn = e.ColumnIndex;

                if (e.RowIndex == dataGridView1.Rows.Count - 1)
                {
                    bindingSource1.Add("");
                }
                dataGridView1.Rows[row].Cells[clmn].Value = openFileDialog1.FileName;
            }
        }

    }
Sameh Serag
"Rows cannot be programmatically added to the DataGridView's rows collection when the control is data-bound."
BlueRaja - Danny Pflughoeft
And if I try to add to the BindingList instead, it gives me the same "Operation is not valid due to the current state of the object"
BlueRaja - Danny Pflughoeft
Oops! I didn't notice that you are binding the gridview to a list! I updated my answer above. Please, check it and let us know the result.
Sameh Serag
Nope - using the `BindingSource.Add()` method gives me spot-on-spot the exact same results as using `cell.Value = something` (see my comment to Zach above)
BlueRaja - Danny Pflughoeft
I found a workaround, +1 for your time anyways though, thank you!
BlueRaja - Danny Pflughoeft
It should be mentioned (for future googlers of this problem) that setting cell.Value still does **not** automatically add a new row: Sameh's code does, though.
BlueRaja - Danny Pflughoeft
+1  A: 

I found a workaround on this page, though I don't know why it works

public MyForm()
{
    InitializeComponent();
    //Create a BindingSource, set its DataSource to my list,
    //set the DataGrid's DataSource to the BindindingSource...
    _bindingSource.AddingNew += OnAddingNewToBindingSource;
}

private void OnAddingNewToBindingSource(object sender, AddingNewEventArgs e)
{
    if(dataGridView1.Rows.Count == _bindingSource.Count)
    {
        _bindingSource.RemoveAt(_bindingSource.Count - 1);
    }
}

I'm getting very sick of spending so much time dealing with Visual Studio bugs...

BlueRaja - Danny Pflughoeft
+1 for question and answer - thanks, this just works and helped us a lot.
Moritz Both