来自工具提示或上下文菜单的相对源绑定

发布于 2024-09-18 10:05:24 字数 394 浏览 9 评论 0原文

我在这里做错了什么?:

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

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

请帮助我。

What am I doing wrong here?:

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

That's just a simplified example, that doesn't work anyway :)
Actually I need to get a value from another property that is in scope of the Window's DataContext.

Help me pls.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

哭泣的笑容 2024-09-25 10:05:24

这很棘手,因为工具提示不是 VisualTree 的一部分。 在这里您可以看到一个很酷的解决方案ContextMenus 也有同样的问题。您可以采用相同的方式获取工具提示。

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

一个很好的方法是在 PlacementTarget 的 Tag 属性中提供所需的实例(例如 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 的奇妙世界来返回
在后面的代码中做事。

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

公共分部类 Window1 : Window
{
    公共窗口1()
    {
        MyString = "这是我的字符串";
    }

    公共字符串 MyString
    {
        得到;
        放;

    }
}


<按钮内容=“测试按钮” 
     Tag="{BindingrelativeSource={RelativeSourceAncestorType={x:类型窗口}}}">
  <按钮.ContextMenu>
    
      ;
    
     

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

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

This is tricky because ToolTip is not part of the VisualTree. Here you see a cool solution for the same problem with ContextMenus. The same way you can go for the ToolTip.

UPDATE
Sadly the link is gone and I have not found the referenced article anymore.
As far as I remember, the referenced blog has shown how to bind to a DataContext of another VisualTree, which is often necessay when binding from a ToolTip, a ContextMenu or a Popup.

A nice way to do this, is to provide the desired instance (e.g. ViewModel) within the Tag-property of the PlacementTarget. The following example does this for accessing a Command-instance of a 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>

I have not tested it and its a long time I did this the last time. Please make a comment if it does not work for you.

UPDATE 2

As the original link that this answer was written about is gone, I hit archive.org and found the original blog entry. Here it is, verbatim from the blog:

Because a ContextMenu in WPF does not exist within the visual tree of
your page/window/control per se, data binding can be a little tricky.
I have searched high and low across the web for this, and the most
common answer seems to be “just do it in the code behind”. WRONG! I
didn’t come in to the wonderful world of XAML to be going back to
doing things in the code behind.

Here is my example to that will allow you to bind to a string that
exists as a property of your window.

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>

The important part is the Tag on the button(although you could just as
easily set the DataContext of the button). This stores a reference to
the parent window. The ContextMenu is capable of accessing this
through it’s PlacementTarget property. You can then pass this context
down through your menu items.

I’ll admit this is not the most elegant solution in the world.
However, it beats setting stuff in the code behind. If anyone has an
even better way to do this I’d love to hear it.

眼藏柔 2024-09-25 10:05:24

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

IsEnabled 绑定到 DataGrid 的“myProperty”值。

我测试了这个并且它有效。绑定方面也有类似的问题。

<ContextMenu
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}"
IsEnabled="{Binding myProperty}"  
>

Per below:
PlacementTarget is the control that owns the ContextMenu (ex: DataGrid). No need for a "tag" property.

IsEnabled binds to the DataGrid's "myProperty" value.

I tested this and it works. Was having similar issue with binding.

<ContextMenu
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}"
IsEnabled="{Binding myProperty}"  
>
翻身的咸鱼 2024-09-25 10:05:24

由于 ContextMenu 不在可视化树中,因此绑定将不起作用。
一个简单的解决方案是使用代理模式,您可以创建一个继承自 DependencyObject 的包装类,并具有一个 DependencyProperty ,它将保留您的 DataContext 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>

发生了什么?
ProxyClassData 属性将绑定到 WindowDataContext,然后它拥有您的所有命令和属性ProxyClass 资源内的 ViewModel
这种方法的另一个好处是可移植性以及在多个视图和项目中的重用。

Because ContextMenu is not in visual tree, binding will not work.
a simple solution is using Proxy Pattern, you can create a wrapper class that inherits from DependencyObject and has a DependencyProperty that will keep a DataContext of your Window, then you can have a resource of the proxy in XAML and finally bind your MenuItem command to your desired command via the proxy object.
Sample Proxy:

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

}

How to use in 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>

What is happening?
Data property of ProxyClass will bind to DataContext of Window, then it has all of your comamnds and properties of your ViewModel inside the ProxyClass resource.
another benefit of this approach is portability and re-using in multiple views and projects.

叹沉浮 2024-09-25 10:05:24

我认为应该这样做:

{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"

I think it should be done like this:

{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文