WPF ComboBox选中事件是否存在?

20
Visual Studio (2015)的XAML编辑器在自动完成ComboBox成员列表中提供了一个名为Selected的事件。为什么会出现这种自动完成错误?
auto complete

Selected不是WPF ComboBox事件(event list),而是ComboBoxItem的一个事件(从ListBoxItem.Selected继承)。
为什么会这样?

编辑

正如@glenThomas的答案所述(感谢),Selected是从Selector继承的附加事件,用于轻松监听所有子选定事件。
但是,如果我在Selected中放置处理程序并构建项目,就会收到错误信息:它不起作用...

'ComboBox'不包含名为'Selected'的定义,也没有接受类型为'ComboBox'的第一个参数的扩展方法'Selected'

2个回答

8

System.Windows.Controls.ComboBox继承自System.Windows.Controls.Primitives.Selector,后者具有一个Selected附加事件。

附加事件允许您将特定事件的处理程序附加到某些子元素,而不是实际定义事件的父元素,即使潜在引发事件的对象或处理目标实例未在其命名空间中定义或拥有该事件。

System.Windows.Controls.Primitives.Selector具有一个SelectedEvent字段,它支持Selected附加事件。

Selected事件的原因是,您可以向控件添加一个事件处理程序,当任何一个子控件引发事件时,该处理程序将被执行。这比为每个ComboBoxItem附加事件处理程序更方便。

至于为什么它包含在XAML代码编辑器的智能感知中,我认为这是一个错误。

Selector类确实有一个公共字段用于选定事件:

public static readonly RoutedEvent SelectedEvent = EventManager.RegisterRoutedEvent( 
            "Selected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Selector));

但是你不能为该事件添加处理程序,因为Selector类没有定义这样的事件:
public event RoutedEventHandler Selected
{ 
    add 
    {
        AddHandler(SelectedEvent, value); 
    }
    remove
    {
        RemoveHandler(SelectedEvent, value); 
    }
}

因此,将其包含在ComboBox的智能感知中是毫无意义的。

但是,ListBoxItemComboBoxItem的基类)确实为您定义了事件以附加处理程序,因此您可以将处理程序附加到ComboBoxItems。


谢谢。但正如你所说,这个事件只在ListBoxItem及其子类中具有意义。如果是这样的话,那么将其定义为“附加”事件,这是标准事件的正常行为。 - dovid
我不明白你的意思。 - Glen Thomas

3

Selected是在Selector类中定义的一个事件,通常与选择器项目一起使用。通常你可以这样编写:

<ListBoxItem Selector.Selected="OnSelected" />

如下图所示,ComboBox也可以是一个项目,因此在智能感知中列出了Selected事件:
<ListBox x:Name="Selector">
    <ComboBox x:Name="Item1" />
    <ComboBox x:Name="Item2" />
</ListBox>

然而,为了使用Selected事件,组合框必须是另一个选择器的项目:
<ComboBox x:Name="Selector1" Selector.Selected="ThisDoesNotWork"/>
<ListBox x:Name="Selector2">
    <ComboBox x:Name="Item1" Selector.Selected="ThisShouldWorkButDoesnt"/>
     <!-- See edit -->
    <ComboBox x:Name="Item2" />
</ListBox>

因为ComboBox也是选择器,所以你不需要写Selector.Selected="...",只需要写Selected="..."。同样地,在附加到Grid时,你不需要写Grid.Column,只需要写Column即可。
<Grid>
    <!-- Grid.Column="1" -->
    <Grid Column="1" />
</Grid>

至少,这解释了Visual Studio中自动完成的行为。

编辑:继承自选择器的控件中既不编译Selector.Selected也不编译Selected=".."语法,可能是由于XAML解析器中存在错误。但是可以使用命名的XML命名空间来解决此问题:

<ListBox x:Name="Selector2"
         xmlns:p="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework">
    <ComboBox x:Name="Item1" p:Selector.Selected="Item1_Selected"/>

你试过你写的代码吗?对我来说,当一个组合框也是列表项时会出现错误。 - dovid
我已经尝试过使用除了ListBoxItem之外的其他控件,但没有使用ComboBox。这似乎是解析器中的一个错误。请查看我的编辑。 - Liero
@Lireo 您的编辑是正确的。但是该事件没有效果,除非它在 ListBoxItem 中触发,否则它永远不会被触发。那么,这个“附加”事件是为什么呢? - dovid
我已经查看了listbox的源代码。如果您将FrameworkElement添加到ListBox.Items中,除了ListBoxItem之外,它将被ListBoxItem包装。这就是为什么ComboBox无法在ListBox内部工作的原因。但是,对于其他选择器,包装成ListBoxItem并不一定是真实的。这可能就是为什么您可以将事件附加到任何元素的原因。 - Liero
1
当选择列表项时,触发其中的动画。选择器定义事件并触发它,但是它在项目上触发。那么为什么不在项目上定义呢?因为项目最终可以是任何元素。ListBox 使用 ListBoxItem,ListView 使用 ListViewItem,DataGrid 使用 DataGridRow,您自己的 Selector 可以使用任何东西。这与附加属性(如 Grid.Row 或 Canvas.Left)的概念相同-您不知道哪些元素需要这些属性。 - Liero
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接