35

我在这里做错了什么?:

 <GridViewColumn>
    <GridViewColumn.CellTemplate>
       <DataTemplate>
          <Button>
            <Button.ToolTip>
              <TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType=Window}}" />

这只是一个简化的示例,无论如何都不起作用:) 实际上,我需要从 Window 的 DataContext 范围内的另一个属性中获取一个值。

请帮帮我。

4

4 回答 4

82

这很棘手,因为 ToolTip 不是 VisualTree 的一部分。在这里,您可以看到针对 ContextMenus 相同问题的一个很酷的解决方案。与工具提示相同的方式。

更新
遗憾的是,链接已经消失,我再也找不到引用的文章了。
据我记得,引用的博客已经展示了如何绑定到另一个 VisualTree 的 DataContext,这在从 ToolTip、ContextMenu 或 Popup 绑定时通常是必需的。

一个很好的方法是在 PlacementTarget 的标记属性中提供所需的实例(例如 ViewModel)。以下示例执行此操作以访问 ViewModel 的命令实例:

<Button Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=Self}}">
  <Button.ContextMenu>
    <ContextMenu>
       <MenuItem Command="{Binding PlacementTarget.Tag.DesiredCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" .../>
    <ContextMenu>
  </Button.ContextMenu>
</Button>

我还没有测试过它,我上次这样做了很长时间。如果它不适合您,请发表评论。

更新 2

由于撰写此答案的原始链接已消失,因此我访问了 archive.org 并找到了原始博客条目。在这里,逐字逐句来自博客:

因为 WPF 中的 ContextMenu 本身不存在于页面/窗口/控件的可视化树中,所以数据绑定可能有点棘手。我已经在网上到处搜索了这个,最常见的答案似乎是“在后面的代码中做”。错误的!我进入 XAML 的美妙世界并不是为了回到背后的代码中做事。

这是我的示例,它将允许您绑定到作为窗口属性存在的字符串。

public partial class Window1 : Window
{
    public Window1()
    {
        MyString = "Here is my string";
    }

    public string MyString
    {
        get;
        set;

    }
}


<Button Content="Test Button" 
     Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
  <Button.ContextMenu>
    <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, 
          RelativeSource={RelativeSource Self}}" >
      <MenuItem Header="{Binding MyString}"/>
    </ContextMenu>
  </Button.ContextMenu>   
</Button>

重要的部分是按钮上的标签(尽管您可以轻松设置按钮的 DataContext)。这存储了对父窗口的引用。ContextMenu 能够通过它的 PlacementTarget 属性访问它。然后,您可以通过菜单项将此上下文向下传递。

我承认这不是世界上最优雅的解决方案。但是,它胜过在后面的代码中设置东西。如果有人有更好的方法来做到这一点,我很想听听。

于 2010-09-08T14:23:37.313 回答
6

如下:
PlacementTarget 是拥有 ContextMenu 的控件(例如:DataGrid)。不需要“标签”属性。

IsEnabled 绑定到 DataGrid 的“myProperty”值。

我对此进行了测试,并且可以正常工作。绑定有类似的问题。

<ContextMenu
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}"
IsEnabled="{Binding myProperty}"  
>
于 2017-06-24T21:45:53.443 回答
-1

因为ContextMenu不在可视树中,绑定将不起作用。一个简单的解决方案是使用代理模式,您可以创建一个继承自DependencyObject并具有一个DependencyProperty将保留DataContext您的 a 的包装类Window,然后您可以在 XAML 中拥有代理的资源,最后MenuItem通过代理将您的命令绑定到您想要的命令目的。
示例代理:

Public class ProxyClass : DependencyObject
{
    Public object Data {get; set;}
   public static readonly DependencyProperty DataProperty = DependencyProperty.Register("DataProperty", typeof(object), typeof(ProxyClass), new FrameworkPropertyMetadata(null));

}

如何在 XAML 中使用:

<Window DataContext="{Binding MyViewModel}">
...
<Window.Resources>
    <ProxyClass Data={Binding} x:Key="BindingProxy"/>

</Window.Resources>
...  
<MenuItem Command="{Binding Source={StaticResource BindingProxy}, Path=Data.MyDesiredCommand"/>
...
</Window>

怎么了?
Dataof 的属性ProxyClass将绑定到DataContextof Window,然后它具有资源ViewModel内部的所有命令和属性ProxyClass
这种方法的另一个好处是可移植性和在多个视图和项目中的重用。

于 2017-01-06T12:40:56.723 回答
-3

我认为应该这样做:

{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
于 2010-09-08T14:24:33.573 回答