数据绑定范围 - 需要澄清

时间:2010-09-28 23:01:51

标签: c# wpf xaml data-binding scope

我一直在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')

1 个答案:

答案 0 :(得分:2)

除了this blog postarchive)之外,还有一些名为继承上下文的内容,除此之外没有太多信息可供查找。

在那篇文章中,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版本中解决这个问题。