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.
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.
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}"
>
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.
I think it should be done like this:
{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
精彩评论