How add command to an ElementMenuItem? - wpf

I am trying to add a command to an ElementMenuItem, but the command can not be fired.
<Grid Name="MenuGrid">
<s:ElementMenu
Name="MainMenu"
ActivationMode="AlwaysActive"
ActivationHost="{Binding ElementName=MenuGrid}"
ItemsSource="{Binding Menu}">
<s:ElementMenu.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Menu}" DataType="{x:Type s:ElementMenuItem}">
<Grid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<behaviours:EventToCommand Command="{Binding Source={StaticResource Locator}, Path=NavigatorMenu.SimpleCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Image Source="{Binding ImageUri}"></Image>
<TextBlock Text="{Binding Title}"
VerticalAlignment="Bottom"
HorizontalAlignment="Center">
</TextBlock>
</Grid>
</HierarchicalDataTemplate>
</s:ElementMenu.ItemTemplate>
</s:ElementMenu>
</Grid>
Does anyone know how to add a command to the menu? Thank you in advance.

No idea what those controls are but if they inherit from normal menus you should use the ItemContainerStyle to hook up commands:
<s:ElementMenu Name="MainMenu" ActivationMode="AlwaysActive"
ActivationHost="{Binding ElementName=MenuGrid}" ItemsSource="{Binding Menu}">
<s:ElementMenu.ItemContainerStyle>
<Style TargetType="s:ElementMenuItem">
<Setter Property="Command"
Value="{Binding Source={StaticResource Locator}, Path=NavigatorMenu.SimpleCommand}" />
</Style>
</s:ElementMenu.ItemContainerStyle>
<s:ElementMenu.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Menu}">
<Grid>
<Image Source="{Binding ImageUri}"/>
<TextBlock Text="{Binding Title}" VerticalAlignment="Bottom"
HorizontalAlignment="Center"/>
</Grid>
</HierarchicalDataTemplate>
</s:ElementMenu.ItemTemplate>
</s:ElementMenu>
This of course assumes that all the bindings actually work, if they don't you should probably debug them...

I don't know why but I find interaction triggers don't work in a Grid. Change your xaml to
<HierarchicalDataTemplate ItemsSource="{Binding Menu}" DataType="{x:Type s:ElementMenuItem}">
<ContentControl>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<behaviours:EventToCommand Command="{Binding Source={StaticResource Locator}, Path=NavigatorMenu.SimpleCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<Image Source="{Binding ImageUri}"></Image>
<TextBlock Text="{Binding Title}"
VerticalAlignment="Bottom"
HorizontalAlignment="Center">
</TextBlock>
</Grid>
</ContentControl>
</HierarchicalDataTemplate>

Related

How to stretch the content of a templated MenuItem using WPF

in my WPF application I have a Menu defined as follows:
<Menu
Grid.Column="1"
MinWidth="50"
MinHeight="50"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Transparent"
Visibility="{Binding Path=ShowSynergies, Converter={StaticResource BoolToVisConverter}}">
<Menu.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</Menu.ItemsPanel>
<MenuItem
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
BorderBrush="Black"
BorderThickness="1"
ItemsSource="{Binding Path=CurrentlyAvailableSynergies, Source={StaticResource ResourceKey=VM}}">
<MenuItem.Header>
<TextBlock
Margin="5"
FontSize="18"
Text="{Binding Path=ActiveSynergy.Synergy, Source={StaticResource ResourceKey=VM}}"
TextAlignment="Center" />
</MenuItem.Header>
<MenuItem.ToolTip>
<TextBlock Text="{Binding Path=ActiveSynergy.Synergy, Source={StaticResource ResourceKey=VM}}" />
</MenuItem.ToolTip>
<MenuItem.Resources>
<HierarchicalDataTemplate DataType="{x:Type ent:VisualSynergy}" ItemsSource="{Binding Path=AvailableDiameters}">
<TextBlock Text="{Binding SynergyText}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type ent:VisualDiameter}">
<TextBlock
VerticalAlignment="Stretch"
Background="Purple"
Text="{Binding Path=VisualValue}">
<intr:Interaction.Triggers>
<intr:EventTrigger EventName="PreviewMouseLeftButtonDown">
<intr:InvokeCommandAction Command="{Binding Path=SelectSynergyCommand}">
<intr:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource ResourceKey=StdMultiConverter}">
<Binding Path="." />
<Binding Path="." Source="{StaticResource ResourceKey=VM}" />
</MultiBinding>
</intr:InvokeCommandAction.CommandParameter>
</intr:InvokeCommandAction>
</intr:EventTrigger>
</intr:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</MenuItem.Resources>
</MenuItem>
</Menu>
Everything is working as intended, all data is bound properly and updated when it should be updated.
My larges issue is that the final TextBlock (the one related to my VisualDiameter type) doe snot stretch to fill the whole MenuItem available space (see screenshot). I've tried also to redefine styles, but since I am inside the MenuItem resources definitions there is something missing and no stretching happens.
Looking ot other questions my issue seems related to the bizzarre definition of TreeView and MenuItem by Microsoft, but I am not confidend enough to start tinkering with basic templates.
You should define an ItemContainerStyle and bind the Command property of the MenuItem container rather than trying to stretch the TextBlock in the DataTemplate:
<MenuItem
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
BorderBrush="Black"
BorderThickness="1"
ItemsSource="{Binding Path=CurrentlyAvailableSynergies}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding SelectSynergyCommand}" />
</Style>
</MenuItem.ItemContainerStyle>
<MenuItem.Header>
...

Add doubleclick-command to wpf-treeview-items

as I found a lot of tasks (questions) to my question, I still have no idea how that works.
Even it's a much too complex example or simply the needed namespace was missing. So after one hour of research, my question...
How do I intergrate doubleclick-command to my WPF treeview (-items)?
Actually, my tree looks like this:
<!-- used Namespace: xmlns:i="http://schemas.microsoft.com/xaml/behaviors" -->
<TreeView DataContext="{Binding ProjectTree}" ItemsSource="{Binding ProjectNode}" DockPanel.Dock="Left"
x:Name="ProjectTree" Margin="0 0 2 0" Grid.Column="0">
<TreeView.ContextMenu>
<ContextMenu StaysOpen="True">
<MenuItem Header="Löschen" Height="20"
Command="{Binding RemoveNodeCommand}"
CommandParameter="{Binding ElementName=ProjectTree, Path=SelectedItem}">
<MenuItem.Icon>
<Image Source="/Icons/32x32/Remove_32x32.png" Width="15" Height="15"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</TreeView.ContextMenu>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding TreeNodeSelectedCommand}"
CommandParameter="{Binding ElementName=ProjectTree, Path=SelectedItem}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding UpdateNodeCommand}"
CommandParameter="{Binding ElementName=ProjectTree, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
<Setter Property="FontWeight" Value="Normal"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<Image Margin="3" Source="{Binding ItemType, Converter={x:Static misc:TreeItemImageConverter.Instance }}" Width="20" />
<TextBlock VerticalAlignment="Center" Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
I don't really understand how the Interaction.Triggers work but should they be the right way?
I'm using the ICommand and a relaycommand for my menu- and button-commands. So far, everything fine in my viewmodels.
Sorry if that is a noob question.
EDIT
As it wasn't a noob question but a noob typo, MouseDoubleClick simply works as SelectedItemChanged so my question was unneccessary. (updated code above)
You can add an interaction trigger in the data template.
I don't have your code so I've adapted a project I already had hanging about to show this working.
My markup, which is of course illustrative rather than cut and paste ready for your purposes:
<TreeView Name="tv" ItemsSource="{Binding Families}" Grid.Row="1" Grid.ColumnSpan="2"
>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Family}" ItemsSource="{Binding Members}">
<Border>
<StackPanel Orientation="Horizontal"
Height="32"
>
<Label VerticalAlignment="Center" FontFamily="WingDings" Content="1"/>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</Border>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:FamilyMember}">
<ContentControl>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding DataContext.TestCommand, RelativeSource={RelativeSource AncestorType=TreeView}}"
CommandParameter="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=TreeViewItem}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<StackPanel Orientation="Horizontal"
Height="32"
x:Name="sp">
<TextBlock Tag="{Binding DataContext.Name,
RelativeSource={RelativeSource AncestorType=TreeViewItem , AncestorLevel=2}
}"
Text="{Binding Name}" />
<TextBlock Text="{Binding Age}" Foreground="Green" />
</StackPanel>
</ContentControl>
</DataTemplate>
</TreeView.Resources>
</TreeView>
The command in my window viewmodel
public class MainWindowViewModel
{
private DelegateCommand<FamilyMember> testCommand;
public ICommand TestCommand
{
get
{
if (testCommand == null)
{
testCommand = new DelegateCommand<FamilyMember>((member) =>
{
MessageBox.Show($"Member's name is {member.Name}");
});
}
return testCommand;
}
}
My tree has family and then each has family members.
If I expand members out I can double click a family member and the message box confirms the name is correct.
Note the contentcontrol in the datatemplate.
You need a control to give you double click support.
Interaction triggers cannot be applied in style setters but you could create an attached behaviour that handles the MouseDoubleClick event for the TreeViewItem:
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="local:YourBehavior.Command" Value="{Binding YourCommand}" />
...
</Style>
Another option is to invoke the command programmtically from the code-behind of the view.

Bind a command to a specific event on an Item of ItemsControl (MVVM)

I would like to bind the invoke of a command when an user double clicks on an Item of my ItemsControl.
So I used System.Windows.Interactivity (v3.5):
<ItemsControl ItemsSource="{Binding AllFiles, Mode=OneWay}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type viewModel:FolderVM}">
<DockPanel Margin="5" Height="70" Width="300">
<DockPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="TextWrapping" Value="WrapWithOverflow"/>
</Style>
</DockPanel.Resources>
<i:Interaction.Triggers>
<!--Exception:Cannot add content of type 'System.Windows.Interactivity.EventTrigger' to an object of type 'System.Windows.Interactivity.TriggerCollection'.-->
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction CommandName="CmdBrowseFolder"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Image Height="70" Width="70" DockPanel.Dock="Left" Source="{Binding Icon}"/>
<Grid Background="LightBlue" DockPanel.Dock="Left">
<WrapPanel Margin="10,0,0,0" Orientation="Vertical">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="Folder"/>
</WrapPanel>
</Grid>
</DockPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModel:FileVM}">
<DockPanel Margin="5" Height="70" Width="300">
<DockPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="TextWrapping" Value="WrapWithOverflow"/>
</Style>
</DockPanel.Resources>
<Image Height="70" Width="70" DockPanel.Dock="Left" Source="{Binding Icon}"/>
<Grid Background="LightBlue" DockPanel.Dock="Left">
<WrapPanel Margin="10,0,0,0" Orientation="Vertical">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding SizeFormatted}"/>
</WrapPanel>
</Grid>
</DockPanel>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
But the following exception triggers as soon as I run the application: Cannot add content of type 'System.Windows.Interactivity.EventTrigger' to an object of type 'System.Windows.Interactivity.TriggerCollection'.
Edit: Some more information:
when I comment the line with InvokeCommandAction no exception anymore. But of course the event doesn't trigger the command
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<!--<i:InvokeCommandAction CommandName="CmdBrowseFolder"/>-->
</i:EventTrigger>
</i:Interaction.Triggers>
Another information: InvokeCommandAction in version 3.5 doesn't contain Command DP, only CommandName and CommandParameter
Seems like there's no solution for the version 3.5.
Bind Events to Commands
I don't know why there's CommandName and CommandParameter DP if we can't use them.

WPF Textboxes and Textblocks not rendered

I have a strange behavior of my application on some computers (it only happens at some customer pcs, i can't reproduce it on my machines).
I have an application to enter and view production scrap data. Every column is an control on it's own. The Expanders are accordion Controls from the WPF Toolkit.
Sometimes Textblocks are not visible:
When the bug happens to Textboxes, they are not even consuming any space:
This is the Datatemplate for the Content of the Accordion Item:
<DataTemplate x:Key="YieldAccContent" DataType="Models:Cell">
<DataTemplate.Resources>
<DataTemplate x:Key="It1">
<StackPanel >
<Label BorderBrush="{x:Static SystemColors.ControlLightBrush}" Padding="1" Height="22" BorderThickness="1" Content="{Binding Value}" Visibility="{Binding Cell.CellGroup.ParentMeasurement.IsEnabled, Converter ={StaticResource boolTovisinv}}"/>
<controls:NumberTextbox Text="{Binding Value, Converter ={StaticResource EmptyStringToNullConverter}, UpdateSourceTrigger=PropertyChanged}" Height="22" Width="80" Visibility="{Binding IsEnabledAndBad, Converter ={StaticResource boolTovis}}" Background="AliceBlue">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus" >
<cmd:EventToCommand Command="{Binding MeasurmentViewModel.LostFocusCommand, Mode=TwoWay, Source={StaticResource Locator}}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</controls:NumberTextbox>
<toolkit:MaskedTextBox Mask ="-99999999" Value="{Binding Value, Converter ={StaticResource EmptyStringToNullConverter}, UpdateSourceTrigger=PropertyChanged}" PromptChar=" " Height="22" Width="80" Visibility="{Binding IsEnabledAndGood, Converter ={StaticResource boolTovis}}" IncludeLiterals="True" IncludePrompt="False" Background="AliceBlue" ValueType="{x:Type sys:Int64}" GotFocus="MaskedTextBox_GotFocus_1" SelectionChanged="MaskedTextBox_SelectionChanged_1">
</toolkit:MaskedTextBox>
</StackPanel>
</DataTemplate>
</DataTemplate.Resources>
<StackPanel >
<Label BorderBrush="{x:Static SystemColors.ControlLightBrush}" BorderThickness="1" Padding="1" Height="22" Width="160" Content="{Binding YieldInput}" Background="Moccasin"/>
<Label BorderBrush="{x:Static SystemColors.ControlLightBrush}" BorderThickness="1" Padding="1" Height="22" Width="160" Content="{Binding YieldOutput}" Background="Moccasin"/>
<Label BorderBrush="{x:Static SystemColors.ControlLightBrush}" BorderThickness="1" Padding="1" Height="22" Width="160" Content="{Binding Yield}" Background="Moccasin"/>
<ItemsControl ItemsSource="{Binding Stations}" ItemTemplate="{StaticResource It1}">
</ItemsControl>
</StackPanel>
</DataTemplate>
This is the Accordion Item itself:
<System_Windows_Controls:Accordion ContentTemplate="{StaticResource Cont}" ItemTemplate="{StaticResource Head}" ItemsSource="{Binding Cells}" SelectedIndex="{Binding SelectedAccItem, Mode=TwoWay}" SelectionMode="{Binding MeasurmentViewModel.SelectionMode, Source={StaticResource Locator}}" HorizontalAlignment="Stretch" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemsChanged" >
<cmd:EventToCommand Command="{Binding MeasurmentViewModel.SelectedItemsChangedCommand, Mode=TwoWay, Source={StaticResource Locator}}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</System_Windows_Controls:Accordion>
What could be the cause of this behavior?
Going by your description about the missing TextBoxes not taking any space, I can only assume that you have a Trigger or Converter attached to their Visibility property. If you put a break point in the Converter that is attached to the offending TextBox, then you can debug whether this is the cause quite easily. I assume that the bool value(s) that you are binding to in the Visibility property is not being set correctly... please check whether this is true.

WPF : InputBindings on a StackPanel

I want to put a command on a ListBoxItem. The ListBoxItem use a DataTemplate composed of a StackPanel (containing an Image and a TextBlock, both using Binding). I want that the doubleclick on that ListBoxItem fire the command.
I have tried this :
<DataTemplate>
<StackPanel>
<StackPanel.Resources>
<CommonUI:CommandReference x:Key="DoubleClickCommand" Command="{Binding Path=DefaultCommand}" />
</StackPanel.Resources>
<StackPanel.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{StaticResource DoubleClickCommand}" />
</StackPanel.InputBindings>
<Image Source="{Binding Path=Thumbnail, IsAsync=True}" IsHitTestVisible="False"/>
<TextBlock Text="{Binding Path=Name}" IsHitTestVisible="False">
</StackPanel>
</DataTemplate>
I have also tried to put the Command Resources on a StackPanel containing this StackPanel, without any change.
I am certain of my binding because when I put the InputBindings part on the TextBlock, it works.
Thanks
Try handling the event in the ListBox instead of the StackPanel:
<ListBox>
<ListBox.Resources>
<CommonUI:CommandReference x:Key="DoubleClickCommand" Command="{Binding Path=DefaultCommand}" />
</ListBox.Resources>
<ListBox.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{StaticResource DoubleClickCommand}" />
</ListBox.InputBindings>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Path=Thumbnail, IsAsync=True}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListBox>
My code finally looks like this :
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel.Resources>
<CommonUI:CommandReference x:Key="DoubleClickCommand" Command="{Binding Path=DefaultCommand}" />
</StackPanel.Resources>
<StackPanel.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{StaticResource DoubleClickCommand}" />
</StackPanel.InputBindings>
<Image Source="{Binding Path=Thumbnail, IsAsync=True}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
Thanks anyway, Mr Poulin.

Resources