locked
Checkbox "Checked" event fires GridViewColumnHeader's Click Event RRS feed

  • Question

  • Hi,

    Inside of a GridView row, I have a checkbox tucked away in a stackpanel here:

    http://dankemper.net/WpfCustomListViewWithExpander.zip

    Just launch the project and click the expander in one of the rows.  Then, click on the checkbox so that a checkmark appears in the checkbox.  You will see that the GridViewColumnHeader's 'Click' event fires.  Why?  Is this a bug?

    Dan
    -DK
    Monday, March 9, 2009 1:28 AM

Answers

  • Hi,

     

    No,It’s not a bug. Since the CheckBox is inherited from ToggleButton base class, which defined Checked routed event like this:

       CheckedEvent = EventManager.RegisterRoutedEvent("Checked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ToggleButton));

     

    And ToggleButton is also derived from ButtonBase base class, ButtonBase defined a Click routed event:

      ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase));

     

    You can see that both Checked and Click use Bubble strategy. When you check a CheckBox in the ListViewItem, it actually fire two event in sequence: firstly the CheckBox implement the Checked event, this event bubble up in the visual tree untill to the tree root.Then Click routed event will fire in the same strategy.

     

    In your test application, you initially want to registr the Click event for GridViewColumnHeader like this:

      _processruleinputvalList.AddHandler(GridViewColumnHeader.ClickEvent, new System.Windows.RoutedEventHandler(GridViewColumnClickEventHandler), false);

     

    But it is the same as you register a Click event for ListView level. The code above has the same effect like this:

    _processruleinputvalList.AddHandler(ButtonBase.ClickEvent, new System.Windows.RoutedEventHandler(GridViewColumnClickEventHandler), false);

     

    Since the Click event for GridViewColumnHeader is inherited from ButtonBase Class,So whenever you check the CheckBox in the row, the Click event will bubble up to the ListView, and ListView already defined a Click handler, so you will see that the CheckBox fire the GridViewColumnHeader.Click event.

     

    How to fix it:

    #1:

    You can defined the Click event for GridViewColumnHeader by itself using EventSetter, not by ListView. so when you check the CheckBox, this event will no longer fires.

       <ListView.Resources>

                        <Style TargetType="GridViewColumnHeader">

                            <EventSetter Event="Click" Handler="GridViewColumnClickEventHandler" />

                        </Style>

       </ListView.Resources>

     

    #2:

    Since the Click event is fired firstly by CheckBox, in the GridViewColumnClickEventHandler, you can determinate that the e.OriginalSource must be CheckBox. Like the code shown below, you can process you logic appropriately.

        void GridViewColumnClickEventHandler(object sender, System.Windows.RoutedEventArgs e)

            {

                if (e.OriginalSource is CheckBox)

                {

                    //do nothing

                }

                else

                {

                    //process your logic

                }

            }

     

    For you information, here is the ToggleButton class ‘s code snippet:

       protected override void OnClick()

            {

                this.OnToggle();

                base.OnClick();

            }

     

    Hope this helps.

     

    Thanks.

     


    Jim Zhou -MSFT
    Friday, March 13, 2009 9:51 AM

All replies

  • Hi,

     

    No,It’s not a bug. Since the CheckBox is inherited from ToggleButton base class, which defined Checked routed event like this:

       CheckedEvent = EventManager.RegisterRoutedEvent("Checked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ToggleButton));

     

    And ToggleButton is also derived from ButtonBase base class, ButtonBase defined a Click routed event:

      ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase));

     

    You can see that both Checked and Click use Bubble strategy. When you check a CheckBox in the ListViewItem, it actually fire two event in sequence: firstly the CheckBox implement the Checked event, this event bubble up in the visual tree untill to the tree root.Then Click routed event will fire in the same strategy.

     

    In your test application, you initially want to registr the Click event for GridViewColumnHeader like this:

      _processruleinputvalList.AddHandler(GridViewColumnHeader.ClickEvent, new System.Windows.RoutedEventHandler(GridViewColumnClickEventHandler), false);

     

    But it is the same as you register a Click event for ListView level. The code above has the same effect like this:

    _processruleinputvalList.AddHandler(ButtonBase.ClickEvent, new System.Windows.RoutedEventHandler(GridViewColumnClickEventHandler), false);

     

    Since the Click event for GridViewColumnHeader is inherited from ButtonBase Class,So whenever you check the CheckBox in the row, the Click event will bubble up to the ListView, and ListView already defined a Click handler, so you will see that the CheckBox fire the GridViewColumnHeader.Click event.

     

    How to fix it:

    #1:

    You can defined the Click event for GridViewColumnHeader by itself using EventSetter, not by ListView. so when you check the CheckBox, this event will no longer fires.

       <ListView.Resources>

                        <Style TargetType="GridViewColumnHeader">

                            <EventSetter Event="Click" Handler="GridViewColumnClickEventHandler" />

                        </Style>

       </ListView.Resources>

     

    #2:

    Since the Click event is fired firstly by CheckBox, in the GridViewColumnClickEventHandler, you can determinate that the e.OriginalSource must be CheckBox. Like the code shown below, you can process you logic appropriately.

        void GridViewColumnClickEventHandler(object sender, System.Windows.RoutedEventArgs e)

            {

                if (e.OriginalSource is CheckBox)

                {

                    //do nothing

                }

                else

                {

                    //process your logic

                }

            }

     

    For you information, here is the ToggleButton class ‘s code snippet:

       protected override void OnClick()

            {

                this.OnToggle();

                base.OnClick();

            }

     

    Hope this helps.

     

    Thanks.

     


    Jim Zhou -MSFT
    Friday, March 13, 2009 9:51 AM
  • Jim,

    A thousand thanks.  Your post was extremely informative. 

    Dan
    -DK
    Friday, March 13, 2009 5:28 PM