我一直在WPF做一些工作,而且我在大多数时候都有我的绑定工作,但我需要在这里澄清范围。我遇到了一些看似简单的操作,需要愚蠢的绑定解决方法,我相信很多都与范围有关。
示例#1 - 在可视树之外,绑定到父级。
<ComboBox x:Name="Combo1" ItemsSource="{Binding SomeListOfStrings}">
<ComboBox.ContextMenu>
<ContextMenu>
<MenuItem Header="{Binding ElementName=Combo1, Path=SelectedItem}" />
<MenuItem Header="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=SelectedItem}" />
</ContextMenu>
</ComboBox.ContextMenu>
</ComboBox>
在这个例子中,我试图将子元素的属性绑定到父元素。由于此项目不在元素下的可视树中,而是仅作为属性,因此无法使用FindAncestor
找到父项。根据我的经验,在这种情况下我也没有与ElementName
绑定运气(尝试Name=""
和x:Name=""
)。
这里的范围是什么? MenuItem如何与ComboBox相关?因为我知道它在这里继承了它的父项DataContext
,为什么它与FindAncestor / ElementName无法接触?
示例#2 - 资源+ StaticResource / DynamicResource
<UserControl x:Name="MainControl" ... />
<UserControl.Resources>
<Style TargetType="ComboBox">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu ItemsSource="{Binding ViewModelsMenuItems}" />
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ComboBox" x:Key="Example2_Style2">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu ItemsSource="{Binding ElementName=MainControl, Path=DataContext.ViewModelMenuItems}" />
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<StackPanel>
<ComboBox />
<ComboBox />
<ComboBox Style="{StaticResource Example2_Style2" />
</StackPanel>
</UserControl>
在这个例子中,我正在尝试为我的用户控件中的所有ComboBox
设置上下文菜单(如果我使用了命名样式,则设置特定的上下文菜单)。由于ContextMenu是在范围之外定义的,并且“设置”为范围,因此我在继承DataContext之前遇到过问题,或者能够使用ElementName(因为该项超出了范围?)。
奖金问题
由于我和ElementName
一起运气很糟糕,有人可以告诉我使用哪个,因为我看到了所有的互联网/书籍。 Name="Whatever"
或x:Name="Whatever"
更新(根据要求)
我得到的绑定失败类型是:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ComboBox', AncestorLevel='1''. BindingExpression:Path=SelectedItem; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Header' (type 'object')
答案 0 :(得分:2)
除了this blog post(archive)之外,还有一些名为继承上下文的内容,除此之外没有太多信息可供查找。
在那篇文章中,ContextMenu是一个没有链接发生的例子。
我可以使用PlacementTarget
属性解决此问题:
<ContextMenu>
<MenuItem Header="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
</ContextMenu>
原始文章消失了;以下是存档的要点:
Nicklight on Silverlight和WPF
什么是继承背景?
Nick Kramer [MSFT] 2006年8月17日
但在我告诉你继承背景之前,我必须解释一下 它解决的问题。曾几何时,财产继承看起来 仅在逻辑树和可视树 - 所以如果一个元素 没有逻辑或可视父级,其属性没有继承 它没有的父母的价值。如果你认为这是有道理的 在代码方面关于世界。但如果你看世界 通过xaml眼镜,有很多地方可以看到一个元素 就像它有一个父母,当它真的没有。请考虑以下事项:
<Button> <Button.Background> <SolidColorBrush>green</SolidColorBrush> </Button.Background> </Button>
快,什么是SolidColorBrush的父母?如果你说按钮,你 会错的 - SolidColorBrush不是可视化树的一部分(它是 不是视觉)。 SolidColorBrush也不是逻辑树的一部分, 因为如果你调用Button.Content,答案就不是了 的SolidColorBrush。因此,此示例中的SolidColorBrush没有父级,所以 它没有继承任何人的财产价值。
起初这似乎是学术性的 - 谁在乎SolidColorBrush 继承?实际上,有几个重要的原因, DataContext属性和Loaded事件。 DataContext是一个 使用{Binding}的默认数据源的继承属性 声明。当你写:
<SolidColorBrush Color="{Binding}"/>
由于您没有指定数据源(以及谁),因此它使用了 DataContext属性。如果这继承了你期望的方式, 一切都很开心。但这很容易写:
<Button DataContext="whatever"> <Button.Background> <SolidColorBrush Color="{Binding}"/> </Button.Background> </Button>
并且混淆你的SolidColorBrush没有继承 DataContext的。同样,Loaded事件最初与之相关联 逻辑树,所以如果你将MediaElement放在VisualBrush中, 视觉树中会有一个空白,你的媒体永远不会得到 一个已加载的事件,永远不会开始播放视频。
这就是我们发明继承上下文的原因。你可以想到它 作为逻辑树2.0 - 继承上下文是一个额外的指针,它 当没有逻辑父或视觉时,属性引擎使用 父母从中获取价值。继承上下文并不能解决所有问题 这个领域存在问题,但是他们解决了很多问题,并且将来也会解决 我们将添加更多的继承上下文指针并解决更多问题。
我们在很多地方建立了继承上下文指针, 我不会尝试列出所有这些,但这里有一些更多 有趣的:
FrameworkElement中的Freezable - 我们的SolidColorBrush / Button 在VisualBrush Triggers和。中的FrameworkElement上面的示例 setter方法
资源词典提出了另一个有趣的案例。假设你 在资源字典中使用DynamicResource:
是否在SolidColorBrush的位置评估了该动态资源 界定?或者刷子被使用的地方?如果是后者,会发生什么 如果你在两个不同的地方使用SolidColorBrush DynamicResource会给出两个不同的答案吗?听起来可能 做作:
<Window.Resources>
`<Color x:Key="color">red</Color>` `<SolidColorBrush x:Key="brush" Color="{DynamicResource color}" /> `
</Window.Resources>
<Button> <Button.Background> <StaticResource ResourceKey="brush"/> </Button.Background> </Button> <Button> <Button.Resources> <Color x:Key="color">blue</Color> </Button.Resources> <Button.Background> <StaticResource ResourceKey="brush"/> </Button.Background> </Button>
但它确实发生在实际代码中。我们选择了第一个解决方案 SolidColorBrush的继承上下文指向资源 字典,而不是它的使用点。
继承上下文非常有用,但我们还没有提到 继承上下文链接到理论上可能的所有地方, 主要是因为当天的时间(添加继承上下文链接 非常难以实现并且不会导致 不受欢迎的行为改变)。可能是最简单的例子 我们没有继承上下文链接是跨越随机属性 元素:
<Button> <Button.ContextMenu> <ContextMenu/> </Button.ContextMenu> </Button>
ContextMenu既不是Button的视觉也不是逻辑子,也不是 上面列出的继承上下文案例之一(ContextMenu不是 一个Freezable)。但是,有了我们可以使用的继承背景概念, 我们希望在将来的WPF版本中解决这个问题。