none
I have question about the selectionChanged event of DataGridView , I need help RRS feed

  • Question

  • Ok,that i work with datagridView in winform  recently.And I have some problem ,so I do some test ,the tests as next

    (1) i create a UserControl and add a DataGridView to it ,then i bind Data at the Load event . it will fire the selectionChanged event 5 times when i add the control to a Form .

    (2)do work as  (1),then i put the form to a MDIForm.it will fire the selectionChanged event 7 times .

    I am confused why the userControl have Instantiated,when it show in form ,it will add more 2 times than before. can some one give me the reason ?the reason always can resolve the test 2.

    at the selectionChanged Event i want to get the dataGridView property rows.Count ,but it is diffrence in next 2 or 4 times.what can i do ?

    Friday, August 3, 2012 1:27 AM

Answers

  • Hi Dieshang,

    Welcome to the MSDN Forum.

    I was able to recreate the issue you mentioned in a sample application. I debugged it to see what was happening.

    When running this, the first three SelectionChanged event notifications come directly out of when the Datasource is being set from the Load event. There are three different code paths that are taken which call OnSelectionChanged on the DataGridView, from the one line of code that sets its DataSource coming out of the Load event.

    The fourth one comes out of OnBindingContextChanged calling DataGridView.CurrentCell.Set, which causes OnSelectionChanged to be raised which then fires the SelectionChanged event.

    The fifth one comes out of OnBindingContextChanged calling DataGridView.RefreshRows to refresh the rows of the DataGridView. When this happens, any currently selected rows are cleared which causes SelectionChanged event to be fired.

    It looks like in the case where it is hosted in MDI, that we have extra BIndingContext calls which lead to the event firing twice more.

    If you don't want these events firing at startup, then you could wire the eventhandler up after the DataGridView is databound. Or you could call BeginInvoke from the Load event to run the code that binds the data. This would let the Load event pop from the stack and we wouldn't get the extra event notifications in that case. Or you could use a combination to get what you are looking for.

    This codes uses the Load event to invoke a delegate via BeginInvoke that calls the LoadSampleData method after the Load event pops from the stack. The LoadSampleData sets the Datasource of the DataGridView control and then wires the eventhandler to its SelectionChanged event. When I run this, I get no events firing at startup and only if I manually click into different cells in the DataGridView.

            private int count = 0;
     
            private void DataGridViewHost_Load(object sender, EventArgs e)
            {
                this.BeginInvoke(new MethodInvoker(delegate()
                {
                    if (!this.DesignMode)
                         LoadSampleData();
                }));
            }
    
    
            private void LoadSampleData()
            {
                data = new List<Person>();
                data.Add(new Person() { Name = "John", Role = "Developer" });
                this.dataGridView1.DataSource = data;
                this.dataGridView1.SelectionChanged += new EventHandler(dataGridView1_SelectionChanged);
            }
            
            private void dataGridView1_SelectionChanged(object sender, EventArgs e)
            {
                count++;
                System.Diagnostics.Debug.WriteLine(count.ToString());
            }
    

    I hope this helps. Please let me know if you have any questions.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, August 13, 2012 1:44 AM
    Moderator

All replies

  • Is this hurt?

    Based on my understanding, it is by design. If you have the source code, you will know how exactly it works.

    Have a nice day.


    Ghost,
    Call me ghost for short, Thanks
    To get the better answer, it should be a better question.

    Monday, August 6, 2012 3:27 AM
  • You may want to put a break point in the event and check the event arguments and call stack for each event. This way you should get a bit more information what is happening and possible cause of the additional events.

    Are you binding to exactly the same data? If not maybe there are two more items in the latter case and that is cusing the additional events.

    Monday, August 6, 2012 8:16 AM
    Moderator
  • Hi Dieshang,

    Welcome to the MSDN Forum.

    I was able to recreate the issue you mentioned in a sample application. I debugged it to see what was happening.

    When running this, the first three SelectionChanged event notifications come directly out of when the Datasource is being set from the Load event. There are three different code paths that are taken which call OnSelectionChanged on the DataGridView, from the one line of code that sets its DataSource coming out of the Load event.

    The fourth one comes out of OnBindingContextChanged calling DataGridView.CurrentCell.Set, which causes OnSelectionChanged to be raised which then fires the SelectionChanged event.

    The fifth one comes out of OnBindingContextChanged calling DataGridView.RefreshRows to refresh the rows of the DataGridView. When this happens, any currently selected rows are cleared which causes SelectionChanged event to be fired.

    It looks like in the case where it is hosted in MDI, that we have extra BIndingContext calls which lead to the event firing twice more.

    If you don't want these events firing at startup, then you could wire the eventhandler up after the DataGridView is databound. Or you could call BeginInvoke from the Load event to run the code that binds the data. This would let the Load event pop from the stack and we wouldn't get the extra event notifications in that case. Or you could use a combination to get what you are looking for.

    This codes uses the Load event to invoke a delegate via BeginInvoke that calls the LoadSampleData method after the Load event pops from the stack. The LoadSampleData sets the Datasource of the DataGridView control and then wires the eventhandler to its SelectionChanged event. When I run this, I get no events firing at startup and only if I manually click into different cells in the DataGridView.

            private int count = 0;
     
            private void DataGridViewHost_Load(object sender, EventArgs e)
            {
                this.BeginInvoke(new MethodInvoker(delegate()
                {
                    if (!this.DesignMode)
                         LoadSampleData();
                }));
            }
    
    
            private void LoadSampleData()
            {
                data = new List<Person>();
                data.Add(new Person() { Name = "John", Role = "Developer" });
                this.dataGridView1.DataSource = data;
                this.dataGridView1.SelectionChanged += new EventHandler(dataGridView1_SelectionChanged);
            }
            
            private void dataGridView1_SelectionChanged(object sender, EventArgs e)
            {
                count++;
                System.Diagnostics.Debug.WriteLine(count.ToString());
            }
    

    I hope this helps. Please let me know if you have any questions.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, August 13, 2012 1:44 AM
    Moderator