Cannot set CommandParameter using ElementName - wpf

I have a TreeView with ContextMenu, and inside that menu I want to bind to a command on VIewModel
<TreeView x:Name="treeView"
ItemTemplate="{StaticResource ItemTemplate}"
ItemsSource="{Binding View}">
<TreeView.ContextMenu>
<ContextMenu>
<telerik:RadMenuItem Header="Remove" Command="{Binding RemoveCommand}" CommandParameter="{Binding ElementName=treeView, Path=SelectedItem, Mode=OneWay}" />
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>
I receive an exception in Output window, like
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=treeView'. BindingExpression:Path=SelectedItem; DataItem=null; target element is 'RadMenuItem' (Name=''); target property is 'CommandParameter' (type 'Object')
I am actually using RadTreeView, but the same applies for TreeView. Why I cannot bind to TreeView's SelectedItem property? I have tried with RelativeSource AncestorType, the same problem.

The problem is that, like the Popup control, it's a different visual tree. The error is telling you that it is trying to find a property called 'CommandParameter' on a 'RadMenuItem', because this is the DataContext it has within the ContextMenu's visual tree.
This will help you: Placement Target
I ended up setting the CommandTarget property of the MenuItem to the ContextMenu's PlacementTarget property, but it doesn't look like that's the approach you're taking. Even still, the PlacementTarget is what you're looking for.

Related

RelativeSource binding does not work

The first textbox below cannot find the parent TabItem however the second textbox can. What am I doing wrong in the first binding?
<TabItem Style="{StaticResource TabItemStyle}" x:Name="zzzzz">
<StackPanel >
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TabItem}}, Path=IsSelected}"></TextBlock>
<TextBlock Text="{Binding ElementName=zzzzz, Path=IsSelected}" />
</StackPanel>
</TabItem>
The error message is: System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TabItem', AncestorLevel='1''. BindingExpression:Path=IsSelected; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
I've never had to set AncestorLevel but I tried setting it to 5000 it still does not work.
Note that I am not setting the binding from the DataTemplate as is shown in this question.
The TabItem is not a visual ancestor of the TextBlock in the content panel of the TabControl so your first binding won't ever work.
If you put a TextBlock in the header of a TabItem, you can bind to the latter using a {RelativeSource}. But the currently visible content panel is a visual child of the TabContol itself rather than a specific TabItem.

WPF Resources.ContextMenu.MenuItem binding to ContextMenu.PlacementTarget.(AttachedProperty)

if the title didn't scare you away, here goes...
<UserControl.Resources>
<!-- so the attached CustomObject can bind to the context -->
<my:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
<!-- for chaining IsNull to Visibility.Collapsed -->
<my:ConverterGroup x:Key="IsNullToVisibility">
<my:IsNullConverter />
<my:VisibilityValuesEqual />
</my:ConverterGroup>
<ContextMenu x:Key="ctxmnu">
<MenuItem Header="Copy" Click="ctxmnu_itmCopy_Click" />
<MenuItem Header="Add" Click="ctxmnu_itmAdd_Click"
IsEnabled="{Binding Source={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu},
Path=PlacementTarget,
Converter={StaticResource IsNotNullConverter}}"
Visibility="{Binding Source={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu},
Path=PlacementTarget.(myAP:APClass.Property),
Converter={StaticResource IsNullToVisibility}}"
/>
</ContextMenu>
</UserControl.Resources>
<Label Content="{Binding Path=Description}" ContextMenu="{StaticResource ctxmnu}">
<myAP:APClass.Property>
<myAP:CustomObject ID="{Binding Source={StaticResource DataContextProxy}, Path=ID}" />
</myAP:APClass.Property>
</Label>
</UserControl>
Basically, I've got a context menu, with two menu items... the first (copy) is always available... the second (Add) is only available if the context menu is applied from a UIElement with the attached property.
Most of this works... attached property is correctly binding via the proxy resource, menuitem click event is able to get the attached property value.
The only thing that DOESN'T work is the MenuItem.IsEnabled/Visibility binding (I was initially going to bind visibility, but lately I'm thinking IsEnabled is a better idea for UX).
The error is in the binding. Standard error 40 in the output window.
System.Windows.Data
Error: 40 :
BindingExpression path error:
'PlacementTarget' property not found on 'object' ''RelativeSource' (HashCode=22838427)'.
BindingExpression:Path=PlacementTarget.(0); DataItem='RelativeSource' (HashCode=22838427);
target element is 'MenuItem' (Name='');
target property is 'Visibility' (type 'Visibility')
Thing is, every article or example I've been able to find (regarding MenuItem binding to PlacementTarget) has the context menu directly on the UIElement, and since the binding occurs when the window/control is instantiated (before the context menu is shown), I'm thinking that the PlacementTarget is NULL and thus error.
Thx in advance!
The problem is you're using the Source property of the binding to assign a RelativeSource. It should be:
IsEnabled="{Binding RelativeSource={RelativeSource
^^^^^^^^^^^^^^
If you look at the error it actually explains it:
'PlacementTarget' property not found on 'object' ''RelativeSource'
The object should've been the context menu.

Access my Window's DataContext inside a DataTemplate

I'm working on a WPF application and I'm using the MVVM pattern. I use MVVMLight to help me handle some Events. I need to forward the "Click" event so that I can pass the arguments as well so that I can know for sure which item that sent the event. If I use the "Command" I cant know for sure that it was the selected item that sent the event - as the item doesnt need to be selected to right click on it.
This is my code for displaying a list of "order lines". There are two types of order lines, and for one of the data types; "AccessoryOrderLine" - I want to add a context menu.
My problem is that I cannot access my Window's DataContext. I've named the root node in the Window "root", and I'm trying to access the root's DataContext, but this failes with the following error:
System.Windows.Data Error: 4 : Cannot find source for binding with
reference 'ElementName=root'.
BindingExpression:Path=DataContext.PackAccessory; DataItem=null;
target element is 'EventToCommand' (HashCode=5903270); target property
is 'Command' (type 'ICommand')
<ListBox HorizontalContentAlignment="Stretch" Margin="10,0,10,10" DockPanel.Dock="Bottom" Grid.Row="1" ItemsSource="{Binding OrderLines, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type m:UnitOrderLine}">
<v:OrderLine />
</DataTemplate>
<DataTemplate DataType="{x:Type m:AccessoryOrderLine}">
<v:OrderLine>
<v:OrderLine.ContextMenu>
<ContextMenu>
<MenuItem Header="Pack 1" IsCheckable="False">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding ElementName=root, Path=DataContext.PackAccessory }" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
</v:OrderLine.ContextMenu>
</v:OrderLine>
</DataTemplate>
</ListBox.Resources>
</ListBox>
I've also tried to use "TemplatedParent" and then I get access to my "OrderLine" DataContext, but I cant get one step further back to my "MainWindowModel".
http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
Found a solution to my problem :)
Found a solution. Updated my original post with the link to my solution.
Its not issue with the DataTemplate. Binding with ElemetName works in all cases except in the case of ContextMenu since it does not lies in the same visual tree as of your window. However, there is one hack where you can use the PlacementTarget property of your context menu.
For details refer to this link - http://social.msdn.microsoft.com/Forums/nl/wpf/thread/526ab350-8788-4bc6-a98a-1e4dee6ad33a
It contains exactly what you are trying to achieve here.
Seems like here are answers for your question:
ElementName Binding from MenuItem in
ContextMenu
WPF MenuItem.Command binding to
ElementName..

WPF Treeview contextmenu IsChecked binding MVVM

I've got a TreeView to which I associate a ContextMenu. That contextmenu has an item whose IsChecked property I want to bind to my ViewModel. Since I am using a tree each treeitem is bound to a subproperty of my ViewModel.
In the VS2010 output window I am seeing this databinding error:
BindingExpression path error: 'IsAutoStart' property not found on 'object' ''HostMgmtViewModel' (HashCode=12565727)'. BindingExpression:Path=IsAutoStart; DataItem='HostMgmtViewModel'
This clearly shows it is trying to bind to my ViewModel and not to the treeitem's associated data. How do I bind to the correct object? Remember my contextmenu is associated with the whole TreeView not to the specific treeitem.
---------- Edit
As xandy pointed out below the resolution to my problem was to bind the IsChecked like this:
{Binding Path=PlacementTarget.SelectedItem.IsDisabledStart, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}
<TreeView Name="tview" Grid.Row="0" Tag="{Binding RelativeSource={RelativeSource Self}, Path=SelectedItem}">
<TreeView.ContextMenu>
<ContextMenu>
<MenuItem Name="miC" Header="{Binding Path=Tag.Key}" DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"></MenuItem>
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>
This is the working code snippet I have. Courtesy of [this].1 All you need is to change the binding path in the tag. I am currently binding the Treeview to a dictionary, so it is the Key property of it. It should not have any problem in binding to any object collections. One interesting finding is context menu is not in part of element tree and this cause the problem. I could bind the text box with no problem:
<TextBlock Grid.Row="1" DataContext="{Binding ElementName=tview, Path=SelectedItem}">
<TextBlock.Text>
<Binding Path="Key" />
</TextBlock.Text>
</TextBlock>
But it is not functioning if for menuitem if I put the same thing.

Help binding command parameter to relative source

I have a ListBox that I have added a ContextMenu to. I want one of the items in the ContextMenu to be bound to a command and I want the parameter passed to that command to be the currently selected item of the ListBox control. Here's my xaml:
<ListBox x:Name="selectedVascularBeds"
ItemsSource="{Binding Path=UserSelectedVascularBeds}"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}"
DisplayMemberPath="VascularBedName">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" Command="{Binding Path=RemoveSelectedVascularBedCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBox}},
Path=SelectedItem}"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
This ListBox is part of a user control that is bound to a view model object. My command method on the underlying object gets called but the parameter passed in is always null.
I have tested changing the binding of the CommandParameter to simply {Binding} which results in the user control's data context being passed into my method - so I know that the command is working and passes parameters correctly. I just can't seem to get the correct binding to access the ListBox's SelectedItem property.
Help?
the context menu is not a descendant of the list box. try an element name binding instead
<MenuItem Header="Remove" Command="{Binding Path=RemoveSelectedVascularBedCommand}" CommandParameter="{Binding ElementName=selectedVascularBeds, Path=SelectedItem}"/>
The ElementName binding also didn't work, the parameter was still null and I found an error in the console output:
System.Windows.Data Error: 4 : Cannot find source for binding with
reference 'ElementName=selectedVascularBeds'.
BindingExpression:Path=DataContext; DataItem=null; target element is
'MenuItem' (Name=''); target property is 'CommandParameter' (type
'Object')
Searching for that error lead me to this link though and it looks like the Context menu is different and I can't achieve what I want the way I'm going about it.
ElementName Binding from MenuItem in ContextMenu

Resources