从ToolTip或ContextMenu的RelativeSource绑定
我在这里做错了什么?
<GridViewColumn> <GridViewColumn.CellTemplate> <DataTemplate> <Button> <Button.ToolTip> <TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType=Window}}" />
这只是一个简单的例子,它不起作用:)实际上,我需要从窗口的DataContext范围内的另一个属性获取值。
帮帮我
这是棘手的,因为ToolTip不是VisualTree的一部分。 在这里你可以看到与ContextMenus相同的问题的一个很酷的解决scheme。 您可以使用工具提示的相同方式。
UPDATE
可悲的是,链接已经消失,我还没有find引用的文章。
据我所知,被引用的博客已经展示了如何绑定到另一个VisualTree的DataContext,这通常是从ToolTip,ContextMenu或Popup绑定时必需的。
一个很好的方法是在PlacementTarget的Tag属性中提供所需的实例(例如ViewModel)。 下面的例子是为了访问ViewModel的Command-instance:
<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>
我还没有testing过,很久以前我做过这个。 如果它不适合你,请发表评论。
更新2
由于这个答案写的原始链接已经不存在了,我打了archive.org并find了原始的博客条目 。 这里是从博客逐字:
由于WPF中的ContextMenu本身不存在于页面/窗口/控件本身的可视化树中,所以数据绑定可能有点棘手。 我在网上search了这个,最常见的答案似乎是“只是在后面的代码中做”。 错误! 我没有进入XAML的美妙世界,回到代码背后做事。
这里是我的例子,这将允许您绑定到作为您的窗口属性存在的string。
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>
重要的部分是button上的标签(尽pipe您可以轻松设置button的DataContext)。 这存储对父窗口的引用。 ContextMenu能够通过它的PlacementTarget属性访问它。 然后你可以通过你的菜单项传递这个上下文。
我承认这不是世界上最优雅的解决scheme。 但是,它在代码背后跳动设置的东西。 如果有人有更好的办法做到这一点,我很乐意听到。
根据以下:
PlacementTarget是拥有ContextMenu的控件(例如:DataGrid)。 不需要“标签”属性。
IsEnabled绑定到DataGrid的“myProperty”值。
我testing了这个,它的工作原理。 有绑定类似的问题。
<ContextMenu DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}" IsEnabled="{Binding myProperty}" >
由于ContextMenu
不在可视化树中,绑定将不起作用。 一个简单的解决scheme是使用代理模式,你可以创build一个inheritance自DependencyObject
的包装类,并有一个DependencyProperty
,它将保持你的Window
的DataContext
,然后你可以在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>
发生什么事?
ProxyClass
Data
属性将绑定到Window
DataContext
,然后在ProxyClass
资源中包含ViewModel
所有comam和属性。
这种方法的另一个好处是在多个视图和项目中的可移植性和重用性。
我认为应该这样做:
{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"