[英]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>
我知道ContextMenu
和MenuItem
与其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
可以同时访问ContextMenu
和MenuItem
。
<!-- 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}}" />
所以我的问题是:
ContextMenu
的名称范围,Button 也可以通过ElementName=myContextMenu
访问“myContextMenu” ?MenuItem
不能通过ElementName=myMenuItem
访问自身,除非设置名称范围?RelativeSource Self
都可以工作?1、为什么不设置MenuContext的namescope,Button也可以通过ElementName=myContextMenu访问myContextMenu?
ContextMenu
元素定义上下文菜单的外观和行为方式。
ContextMenu
class 的属性用于定义 position 和ContextMenu
的行为。 [...]如果将
ContextMenu
分配给FrameworkElement.ContextMenu
或FrameworkContentElement.ContextMenu
属性,则ContextMenuService
class 处理上下文菜单操作以响应用户交互。 [...]
ContextMenu
会自动放置在Popup
控件中。
ContextMenu
已分配给Button
的ContextMenu
属性,并且它在整个运行时中仍然存在,其中包含您创建的所有菜单项。 它与Button
位于相同的名称范围内,因为名称范围是在解析 XAML 时在加载时创建的,此时它是Button
的一部分。
在 WPF 中,XAML 名称范围在 XAML 页面加载时的根元素上创建。 从页面根开始的 XAML 页面中指定的每个名称都添加到相关的 XAML 名称范围中。
因此,与ElementName
的Binding
成功解析,因为它在单个名称范围中运行。
2. 为什么MenuItem不能通过ElementName=myMenuItem访问自己,除非设置namescope?
如您所见, ContextMenu
与Button
在同一名称范围内。 打开它时, ContextMenu
仍被分配给Button
的ContextMenu
属性,但承载它的新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
orx: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.