I have this code structure in a C# WPF program:
<MenuItem Header="father"
Visibility="{Binding Path=IsEnabled,
RelativeSource={RelativeSource Self},
Converter ={StaticResource BoolToVisibleConverter}}"
Command="{Binding SetFatherCommand}">
<MenuItem Header="son1"
Command="{Binding SetSon1Command}"
CommandParameter="{x:Static Types:CableType.Phase1}"
Visibility="{Binding Path=IsVisible, Converter={StaticResource BoolToVisibleConverter}}"/>
</MenuItem>
When I click on the MenuItem father the command SetFatherCommand is not executed but if I comment the lines corresponding to the MenuItem son1 the command from the MenuItem father will be executed.
I am a bit lost, I think the command binding in the child is somehow affecting the command binding in the father but I don´t understand why and how can I solve it. I will appreciate any input.
The Command property does not work on MenuItem's which have sub MenuItem's
Related
I am having a WPF binding issue that I cannot figure out. I have a ContextMenu template that is formatted as shown:
<ContextMenu x:Key="CopyPasteContextMenu">
<MenuItem Header="AlternateDelete"
Command="{Binding Path=PlacementTarget.Tag.DataContext.AlternateDeleteCommand,
RelativeSource={RelativeSource Self}, Mode=OneWay}"/>
</ContextMenu>
The context menu is being used in the DataTemplat, and the binding for the Tag on the Border is finding the PropertyEditorView correctly, I just can't get it from the border to the contextmenu.
<DataTemplate x:Key="PropertyValueCellViewingTemplate" DataType="viewModels:IConfigurationItemViewModel">
<Border x:Name="ValueCellBorder"
Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type views:PropertyEditorView}}}"
ContextMenu="{StaticResource CopyPasteContextMenu}"
Style="{StaticResource PropertyGridValueCellBorderStyle}">
(...)
</Border>
</DataTemplate>
The tag can bind properly to my view model which is called “PropertyEditorViewModel”. I can see this while debugging the system in the visual tree. When I drill into my Context Menu, the binding is not happening properly.
For my Command to work, I need it to bind properly to the Command to PropertyEditorView view model command called “AlternateDeleteCommand”.
public class PropertyEditorViewModel : DisposableViewModelBase, IPropertyEditorViewModel
{
public ICommand AlternateDeleteCommand { get; set; }
Looked at this for a day so far, and not sure why my binding isn't working on the context menu, anyone got something I'm missing?
Thanks!
Doesn't the relative source need to be on the context menu and not on the menu item? Since you are checking the placement target of the context menu?
<MenuItem Header="AlternateDelete"
Command="{Binding Path=PlacementTarget.Tag.DataContext.AlternateDeleteCommand,
RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Mode=OneWay}" />
I'm a little bit lost with bindings.
I tried so many things in the last hour, I cannot enumerate all of them. I have an issue with a contextMenu inside a DataTemplate.
To explain: I have a UserControl. Its dataContext is itself. Inside this UserControl, I have an ItemsControl to represent a list of Hyperlink. My ItemsControl itemsSource is bound (it is composed of objects elements).
I redefined ItemsControl.ItemTemplate. Inside, I create a HyperLink, with TextBlock as child to make it work, and on this TextBlock, I set a ContextMenu by doing the following.
<TextBlock.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Enregistrer la pièce jointe" Foreground="Black">
<MenuItem Header="Dans le dossier patient" Command="{Binding DataContext.SaveAttachmentIntPatientFolderCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding FilePath}" Foreground="Black" />
<MenuItem Header="Enregistrer sous ..." Command="{Binding DataContext.SaveAttachmentAsCommand}" CommandParameter="{Binding FilePath}" Foreground="Black" />
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
So I have
UserControl --> ItemsControl --> ItemTemplate --> HyperLink --> TextBlock --> ContextMenu --> ContextMenuItem
I know that my first relative source doesn't work, I have a binding error. What I want is to bind on my UserContorl datacontext, which have these commands.
How can I proceed?
Thanks
ContextMenu takes the DataContext of the ItemsControl and so it cannot access the ViewModel directly. Also It is not part of the VisualTree and so you cannot do RelativeSource binding. So We need to get the DataContext of the UserControl through TextBlock's Tag property and then bind to ContextMenu.
You refer the below code.
<TextBlock Text="{Binding }" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}">
<TextBlock.ContextMenu>
<ContextMenu >
<MenuItem Header="Enregistrer la pièce jointe" Foreground="Black">
<MenuItem Header="Dans le dossier patient"
Command="{Binding Path=PlacementTarget.Tag.SaveAttachmentIntPatientFolderCommand,
RelativeSource={RelativeSource AncestorType=ContextMenu}}"
Foreground="Black" />
<MenuItem Header="Enregistrer sous ..."
Command="{Binding Path=PlacementTarget.Tag.SaveAttachmentAsCommand,
RelativeSource={RelativeSource AncestorType=ContextMenu}}"
Foreground="Black" />
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
I am using the Command pattern with (among other things) a context menu on a TreeViewItem, which uses HierarchicalDataTemplates. The MainWindowViewModel (a static resource for the Window) has properties that expose singleton objects that in turn have properties that represent the commands. I am able to execute the command just fine, but some of the commands need to pass the TreeViewItem's DataContext as the CommandParameter.
Here's a specific example:
One node of the tree has the ItemsSource bound to an ObservableCollection of individual AnalysisMain objects. Each of the resulting subnodes has a ContextMenu (with a DataContext bound to the AnalysisController) which has (among others) a Remove MenuItem. The Remove MenuItem's Command property is bound to the CommandRemove command on the AnalysisController singleton object (and it executes just fine). But this also requires the CommandParameter to be bound to the AnalysisMain object that serves as the DataContext for the subnodes in the tree. I have tried using RelativeSource with the AncestorType set to TreeViewItem and the Path set to DataContext:
<HierarchicalDataTemplate DataType="{x:Type vmAnalysis:AnalysisMain}">
<WrapPanel Orientation="Horizontal">
<Image Source="Analysis\Icon_Analysis_Main_16_Normal.png" Margin="0,0,2,0" Width="16"/>
<TextBlock Text="{Binding TreeViewTitle}">
<TextBlock.ContextMenu>
<ContextMenu DataContext="{StaticResource mainWindowViewModel}">
<MenuItem Header="Remove" Command="{Binding Path=AnalysisController.CommandRemove}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}, AncestorLevel=4}, Path=DataContext}">
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</WrapPanel>
</HierarchicalDataTemplate>
Without the AncestorLevel set, when I open the ContextMenu, I get the following in the Output window:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TreeViewItem', AncestorLevel='4''. BindingExpression:Path=DataContext; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'CommandParameter' (type 'Object')
I have tried several values for the AncestorLevel to no avail.
From examining the Visual Tree in Christian Mosers WPF Inspector, I don't see the context menu in the visual tree. Although the TreeViewItem shows the DataContext object. I just need a way to "navigate" to it in order to bind to it.
As an alternative, I have tried leaving the ContextMenu DataContext alone and setting the Command Binding's Source to point back to the AnalysisController. This also works for executing the command, but I am not able to bind to the TreeViewItem's DataContext for the CommandParameter:
<ContextMenu>
<MenuItem Header="Remove" Command="{Binding Source={StaticResource mainWindowViewModel}, Path=AnalysisController.CommandRemove}"
CommandParameter="{Binding Source={RelativeSource Self}, Path=DataContext}">
</MenuItem>
</ContextMenu>
I have also tried just using CommandParameter="{Binding}", which also doesn't work. (In both cases, I just get null sent as the parameter. No warning / error is written to the Output window.) EDIT: For anyone else with this problem, the second option was doomed from the beginning, because I mistakenly put in Source={RelativeSource Self}, which would refer to the MenuItem and not the TreeViewItem. However, changing this with AncestorType / AncestorLevel makes no difference.
You have to use PlacementTarget property of the ContextMenu
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu
DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
</ContextMenu>
</Setter.Value>
</Setter>
And on your MenuItem do a RelativeSource to ContextMenu then use PlacementTarget.DataContext as your binding to your CommandParameter
I have a problem with command binding in WPF. I have the following xaml:
<ItemsControl ItemsSource="{Binding Entity}" Name="Lst">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Content="qwerty" Command="{Binding ElementName=Lst, Path=DataContext.SaveCommand}" >
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Send2" Command="{Binding ElementName=Lst, Path=DataContext.SaveCommand}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
As you can see Button and its ContextMenu have the similar command-bindings. But when i click button its command is firing and when i click context menu's item its command isn't firing. Where am i wrong? Thanks in advance!
I had a similar problem before and solved it by passing the datacontext through the tag property of the container as below. I have it working on a grid ContextMenu but dont see any reason why this wont work on a button. Let me know if you have any problem
<Button Content="qwerty" Tag="{Binding DataContext,ElementName=Lst}" Command="{Binding ElementName=Lst, Path=DataContext.SaveCommand}" >
<Button.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Send2" Command="{Binding SaveCommand}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
The ContextMenu being separate from the visual tree, you cannot bind with and element outside of it.
If you check your output window, you should have a message saying that it can't find the object "Lst"
A common and easy workaround would be to manually set the DataContext in code-behind (note: this is not breaking MVVM at all. You are just performing a pure UI operation of linking DataContexts together):
In your Xaml:
<Button.ContextMenu>
<ContextMenu Opened="OnContextMenuOpened">
<MenuItem Header="Send2" Command="{Binding ElementName=Lst, Path=DataContext.SaveCommand}" />
</ContextMenu>
</Button.ContextMenu>
In code-behind:
public void OnContextMenuOpened(object sender, RoutedEventArgs args)
{
(sender as ContextMenu).DataContext = Lst.DataContext;
}
You are therefore linking the DataContext every time the ContextMenu is opened (so if Lst's DataContext changes, your ContextMenu will as well)
Alternatively (cleaner if you are bound to use it a lot of times), get the BindingProxy from this article: http://tomlev2.wordpress.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/ and it'll do the trick!
I am trying to get some binding code working. Bascially I want to bind the IsEnabled property of an element of my grid's context menu with a value of the selected row in the grid.
I have it working with this:
<my:DataGrid.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.SelectedItem, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Grant Access" IsEnabled="{Binding Connectable}"/>
</ContextMenu>
</my:DataGrid.ContextMenu>
But I want to do it this way and it's not working. It doesn't error but just doesn't disable the menu item. Any idea why?
<my:DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Grant Access" IsEnabled="{Binding Path=SelectedItem.Connectable, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type my:DataGrid}}}"/>
</ContextMenu>
</my:DataGrid.ContextMenu>
Try using ElementName binding instead of Ancestor binding. ContextMenu is not part of Grid's visual tree.
--edit--
Ah, I was wrong. ElementName binding (example given below) would also not work with ContextMenu. It is not part of DataGrid's visual tree. That is why it cannot see that DataGrid and thus cannot reference it. You will have to do it using the first method.
Any reason why you don't want to do it that way?
<DataGrid.ContextMenu>
<ContextMenu DataContext="{Binding SelectedItem, ElementName=DataGrid1}">
<MenuItem Header="Grant Access"
IsEnabled="{Binding Connectable}" />
</ContextMenu>
</DataGrid.ContextMenu>
If you look at the output window in Visual Studio while in Debug mode, you'll get details of the binding error - which may shed some light on your problem.