【问题标题】:WPF: How to prevent CheckBox.Checked event from being fired for ComboBox as a ToggleButton?WPF:如何防止 CheckBox.Checked 事件被触发为 ComboBox 作为 ToggleButton?
【发布时间】:2020-04-10 20:46:06
【问题描述】:

我在一个窗口中有很多控件,包括复选框和组合框。我想跟踪 CheckBox.IsChecked 事件,所以我在 Windows 级别定义了一个事件处理程序为

<Grid CheckBox.Checked="OnModified" CheckBox.Unchecked="OnModified">

问题是 ComboBox 在鼠标单击项目后也会立即触发相同的事件。我认为我的事件处理程序应该只捕获 CheckBox 的 Checked 事件,而不是 ToggleButton 的。我错过了什么吗?

编辑: 正如我在下面所指出的,我认为它会以这种方式工作,因为我阅读了 Matthew MacDonald 的书“Pro WPF in C# 2010”。 在第164页,他先给出了这个示例代码:

<StackPanel Button.Click="DoSomething" Margin="5">   
  <Button Name="cmd1">Command 1</Button> 
  <Button Name="cmd2">Command 2</Button> 
  <Button Name="cmd3">Command 3</Button> 
  ... 
</StackPanel>  

然后,他特别注明:

注意 Click 事件实际上是 在 ButtonBase 类中定义和 由 Button 类继承。如果你 将事件处理程序附加到 ButtonBase.Click,那个事件处理程序 将在任何时候使用 ButtonBase 派生控件被单击 (包括Button、RadioButton、 和 CheckBox 类)。如果你附上 Button.Click 的事件处理程序, 它仅用于 Button 对象。

现在,是我误解了他,还是他的笔记错了?

【问题讨论】:

  • 您的事件处理程序是如何“附加”的?一些代码会很好!
  • 好的,我编辑了问题以包含一些代码。

标签: wpf combobox checkbox routedevent


【解决方案1】:

实际上并没有单独的CheckBox.Checked 事件。如果您查看此页面:

找到Checked事件,你会看到它继承自ToggleButton,所以ToggleButton.CheckedCheckBox.Checked是同一事件的两个不同名称。

由于您订阅的是“通配符”事件,因此您可以在事件处理程序中检查发送者或来源,看看您是否感兴趣。

编辑:

为了解决您对书名引用的后续问题,我认为该引用至少具有误导性。这是一个反例,它显示了 CheckBoxButton 事件做出反应,即使 CheckBox 不是从 Button 派生的:

<CheckBox Button.Click="CheckBox_Click"/>

当然没有Button.Click 事件,只有ButtonBase.Click 事件,但这就是报价的关键所在。如果这句话是真的,要么不允许这种语法,要么不会触发事件,这两者都不是真的。

【讨论】:

  • 我以为我在某处(在一本书中?)读到 CheckBox.Checked 和 ToggleButton.Checked 事件之间存在区别,即使前者是从后者继承的。显然,这是我的误解。但是,我认为如果我们确实有这种区别会更有用。不管怎样,我接受了你的回答。
  • 嘿嘿,我刚刚找到了我的误解的根源:MacDonald's Pro WPF in C# 2010的第164页,他写道:“注意Click事件实际上是在ButtonBase类中定义的,由Button类继承. 如果将事件处理程序附加到 ButtonBase.Click,则当单击任何 ButtonBase 派生控件(包括 Button、RadioButton 和 CheckBox 类)时,将使用该事件处理程序。如果将事件处理程序附加到 Button.Click,它是仅用于 Button 对象。”对吗?
  • 出于我所描述的原因,您可以编写&lt;CheckBox Button.Click="CheckBox_Click"/&gt;,即使CheckBox 不是从Button 派生的,并且仍将调用处理程序。因此,我会说这本书至少具有误导性。
【解决方案2】:

因为您在网格上设置事件,所以网格中包含的具有Checkbox.Checked 路由事件的任何子级都将响应该事件。在您的情况下,ComboboxItem 碰巧使用相同的路由事件(我相信其他控件也可能重用它)

处理此问题的最简单方法是向您的处理程序添加一个测试,如下所示:

private void OnModified(object sender, EventArgs args)
{
    if ( sender is CheckBox )
    {
        CheckBox ckBox = sender as CheckBox;
        // do stuff with ckBox
    }
}

【讨论】:

    【解决方案3】:

    发生这种情况是因为两个事件都在元素树中冒泡并到达您的处理程序(CheckBox 继承 ToggleButton,因此 CheckBox.CheckedToggleButton.Checked 实际上是相同的事件)。你无法阻止这一点。您可以做的是检查事件是否由CheckBox 引发。可以这样做:

    private void OnModified(object sender, RoutedEventArgs e)
    {
        // Filter the event by its source
        if (e.Source.GetType() != typeof(CheckBox))
            return;
    
        // Your handling code         
    }
    

    【讨论】:

      【解决方案4】:

      我曾经通过检查它是否聚焦来防止 Checkbox.Checked 事件。因为当它从绑定中触发时,它不是聚焦的,但是当你点击它时它就会聚焦。

       if(cbo.IsFocused){ // code here }
      

      希望这会有所帮助。 布莱里姆。

      【讨论】:

        【解决方案5】:

        我是“Pro WPF in C# 2010”的作者,我可以确认注释框中的文本属于“我抽什么烟?”类别。根据您在标记中引用它的方式,Click 事件之间没有区别。

        马修

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-01-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-17
          • 1970-01-01
          相关资源
          最近更新 更多