繁体   English   中英

ContextMenu 中的 ElementName 绑定

[英]ElementName Binding in ContextMenu

假设我有一个名为“ myButton ”的Button ,在其ContextMenu (名为“ myContextMenu ”)内,我有一个名为“myMenuItem”MenuItem

<Button Name="myButton">
    <Button.ContextMenu>
        <ContextMenu Name="myContextMenu">
            <MenuItem Name="myMenuItem" />
        </ContextMenu>
    </Button.ContextMenu>
</Button>

我知道ContextMenuMenuItem与其PlacementTarget myButton不在同一可视树或名称范围内,因此使用ElementName ,绑定将失败。 通过使用NameScope.SetNameScope() ,我可以使ContextMenu在同一个名称范围内,然后使绑定成功。

<!-- this will succeed only if setting the namescope in code-behind -->
<MenuItem Name="myMenuItem" Command="..." CommandParameter="{Binding ElementName=myButton}" />

但是,如果不在代码隐藏中设置名称范围, Button可以同时访问ContextMenuMenuItem

<!-- this will succeed no matter the namescope is set in code-behind -->
<Button Name="myButton" Command="..." CommandParameter="{Binding ElementName=myContextMenu}">

此外,我还注意到MenuItem甚至无法使用ElementName访问其自身或其父ContextMenu 但是通过使用RelativeSource Self ,绑定将成功。

<!-- both will fail unless setting namescope in code behind -->
<MenuItem Name="myMenuItem" Command="..." CommandParameter="{Binding ElementName=myContextMenu}" />
<MenuItem Name="myMenuItem" Command="..." CommandParameter="{Binding ElementName=myMenuItem}" />
<!-- succeed even without setting namescope -->
<MenuItem Name="myMenuItem" Command="..." CommandParameter="{Binding RelativeSource={RelativeSource Self}}" />

所以我的问题是:

  1. 为什么即使不设置ContextMenu的名称范围,Button 也可以通过ElementName=myContextMenu访问“myContextMenu”
  2. 为什么MenuItem不能通过ElementName=myMenuItem访问自身,除非设置名称范围?
  3. 为什么无论名称范围或可视树如何, RelativeSource Self都可以工作?

1、为什么不设置MenuContext的namescope,Button也可以通过ElementName=myContextMenu访问myContextMenu?

ContextMenu元素定义上下文菜单的外观和行为方式。

ContextMenu class 的属性用于定义 position 和ContextMenu的行为。 [...]

如果将ContextMenu分配给FrameworkElement.ContextMenuFrameworkContentElement.ContextMenu属性,则ContextMenuService class 处理上下文菜单操作以响应用户交互。 [...]

ContextMenu会自动放置在Popup控件中。

ContextMenu已分配给ButtonContextMenu属性,并且它在整个运行时中仍然存在,其中包含您创建的所有菜单项。 它与Button位于相同的名称范围内,因为名称范围是在解析 XAML 时在加载时创建的,此时它是Button的一部分。

在 WPF 中,XAML 名称范围在 XAML 页面加载时的根元素上创建。 从页面根开始的 XAML 页面中指定的每个名称都添加到相关的 XAML 名称范围中。

因此,与ElementNameBinding成功解析,因为它在单个名称范围中运行。

2. 为什么MenuItem不能通过ElementName=myMenuItem访问自己,除非设置namescope?

如您所见, ContextMenuButton在同一名称范围内。 打开它时, ContextMenu仍被分配给ButtonContextMenu属性,但承载它的新Popup被分配为其父级。 这也意味着它位于不同的视觉树中。 然而,它与Button所指的实例相同 这非常重要,因为名称范围不会在初始分配后自动重新分配。

解析 XAML 的时刻表示创建和定义 WPF XAML 名称范围的时刻。 If you add an object to an object tree at a point in time after the XAML that produced that tree was parsed, a Name or x:Name value on the new object does not automatically update the information in a XAML namescope.

总之, ContextMenu只是Popup的父级,但它仍然与Button处于相同的名称范围内。 这只能通过将其添加到代码中的目标命名空间来手动更改。

To add a name for an object into a WPF XAML namescope after XAML is loaded, you must call the appropriate implementation of RegisterName on the object that defines the XAML namescope, which is typically the XAML page root. 如果名称未注册,则添加的 object 无法通过 FindName 等方法按名称引用,并且您无法将该名称用于 animation 定位。

3. 为什么RelativeSource Self 工作与namescope 或visual tree无关?

RelativeSource不使用名称来解析元素,因此它独立于实际的名称范围,但它依赖于可视化树。

实现一个标记扩展,描述绑定源相对于绑定目标的 position的位置。

ContextMenu的具体情况下,显然MenuItem上的RelativeSource绑定可以自行解析,以及ContextMenu ,因为它们都是同一可视树的一部分。 但是,它无法解析Button ,因为ContextMenu在运行时的根是被分配为其父级的Popup

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM