DataGridView focus problem when deleting the last record

  • Thread starter Thread starter Tomasz J
  • Start date Start date
T

Tomasz J

Hello Developers,



I have a problem I really do not how to correctly handle.



Very simple scenario:



DataGridView bound to BindingSource, BindingNavigator attached,
BindingSource bound to a DataTable, let's say, with just one column. Also, I
have a TextBox bound to my BindingSource and its the only column.



When there are no records, my TextBox should be disabled, when I add a new
record focus should be set on my TextBox. I accomplish that handling two
events:



private void bindingNavigatorAddNewItem_Click(object sender, EventArgs e) {

this.myTextBox.Focus();

}

private void myBindingSource_PositionChanged(object sender, EventArgs e) {

this.myTextBox.Enabled = (myBindingSource.Current != null);

}





The problem:



When I delete the last record using BindingNavigator my TextBox gets
disabled and focus moves on DataGridView. But the DataGridView does not know
yet that the only row is gone. That triggers the following exception:



System.IndexOutOfRangeException: Index -1 does not have a value.

at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)

at System.Windows.Forms.CurrencyManager.get_Current()

at
System.Windows.Forms.DataGridView.DataGridViewDataConnection.OnRowEnter(DataGridViewCellEventArgs
e)

at System.Windows.Forms.DataGridView.OnRowEnter(DataGridViewCell&
dataGridViewCell, Int32 columnIndex, Int32 rowIndex, Boolean
canCreateNewRow, Boolean validationFailureOccurred)

at System.Windows.Forms.DataGridView.OnEnter(EventArgs e)

at System.Windows.Forms.Control.NotifyEnter()

at System.Windows.Forms.ContainerControl.UpdateFocusedControl()



I can even handle deletions through code by calling:
myBindingSource.RemoveCurrent()

, but how to do this, so the DataGridView gets notified immediately, before
it accidentally receives focus?



I know I can set focus somewhere else, before disabling the TextBox, but I
am looking for some more "elegant" solution.



Thank you for any pointers.



Tomasz J
 
Hello Tomasz,

I'm afraid to say I cannot understood your issue very clear.
Would you please clarify the follow two issues for me?
Then, we can perform further analyze.

1) Why do you say that focus will move on DataGridView after the last
recored deleted?
Do you set the focus on DataGridView in your code?
If so, would you please paste it in newsgroup?

2) Why do you think the DataGridVIew doesn't know the only row is gone?
As far as I know, if we set the datasource of DataGridView to
BindingSource. This DataGridView will be refreshed automaticlly.

I have created a table (one column) in SQL database, and add BindingSoure,
BindingNavigator, DataGridView,Textbox on my side. But I'm failed to
reproduce this issue.

If possible, would you please give me a detailed reproduce steps? This will
help on the research very much. Thanks.

Have a great day, Please let me know if you have any more concern. We are
glad to assist you.
Best regards,

Wen Yuan
Microsoft Online Community Support
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hello WenYuan,

Here are the steps to reproduce the problem:
1. in the following order add new BindingSource to a new form,
2. add new BindingNavigator,
3. add new DataGrid View,
4. set dataGridView1.DataSource to bindingSource1
5. set bindingNavigator1.BindingSource to bindingSource1
6. paste this code into form constructor:

DataTable dt = new DataTable();
dt.Columns.Add("test", typeof(string));
bindingSource1.DataSource = dt;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;
dataGridView1.AutoGenerateColumns = true;

7. Create bindingSource1 PositionChanged event handler and paste the
following code:

if (bindingSource1.Current == null) {
//dataGridView1.TabStop = false;
textBox1.Enabled = false;
} else {
//dataGridView1.TabStop = true;
textBox1.Enabled = true;
if (((DataRowView)bindingSource1.Current).IsNew) {
textBox1.Focus();
}
}

See what happens when you add and remove the first record using binding
navigator.

Commented out lines seem to remedy the problem - the best solution I found
so far.

Thank you,

Tomasz J
 
Hello WenYuan,

I am sorry, I missed something. Please scratch out the previous post.

Here are the steps to reproduce the problem:

1. in the following order add new BindingSource to a new form,
2. add new BindingNavigator,
3. add new DataGridView,
4. add new TextBox,
5. set dataGridView1.DataSource to bindingSource1
6. set bindingNavigator1.BindingSource to bindingSource1
7. paste this code into form constructor:

DataTable dt = new DataTable();
dt.Columns.Add("test", typeof(string));
bindingSource1.DataSource = dt;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;
dataGridView1.AutoGenerateColumns = true;
textBox1.DataBindings.Add(new Binding("Text", bindingSource1, "test",
true));

8. Create bindingSource1 PositionChanged event handler and paste the
following code:

if (bindingSource1.Current == null) {
//dataGridView1.TabStop = false;
textBox1.Enabled = false;
} else {
//dataGridView1.TabStop = true;
textBox1.Enabled = true;
if (((DataRowView)bindingSource1.Current).IsNew) {
textBox1.Focus();
}
}

See what happens when you add and remove the first record using binding
navigator.

Commented out lines seem to remedy the problem - the best solution I found
so far.

Thank you,

Tomasz J
 
Hello Tomasz,
Thanks for your reply.

I have reproduced the issue on my side.

I'm afraid PositionChanged is not the right event for your requirement.

According to your description and Code, what you need is as following:
When there is no data in BindingSource, the textbox is disabled.
When there is any data in BindingSource, the textbox is enabled.
When we are adding data, the textbox should be focused.

Have you tried ListChanged event? This event will monitor the data in
BindingSource. We can check count and ListChangedTyped property to achieve
what you need.
This method works fine on my side. Would you please try it ?
void bindingSource1_ListChanged(object sender, ListChangedEventArgs e)
{
if (this.bindingSource1.Count == 0)
textBox1.Enabled = false;
else
textBox1.Enabled = true;

if (e.ListChangedType == ListChangedType.ItemAdded)
textBox1.Focus();
}

Hope this helps, please let me know if this way works fine on your side. We
are glad to assist you.
Have a great day,
Best regards,

Wen Yuan
Microsoft Online Community Support
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hello Tomasz,
Thanks for your reply.

I'm glad to hear my method helps.

The issue may related to the BindingSource implement. But, ListChanged
event should be the right event in your issue.

If you face any further issue, please feel free to let me know. We are glad
to assist you.

Have a great day,
Best regards,

Wen Yuan
Microsoft Online Community Support
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Back
Top