MenuItem Icon not clickable? WPF - wpf

I have a menuitem that contains a sub menu of menuitems. For some reason, to set off the command i have to click the actual menuitem and not the menuitem icon as well. i.e. clicking the menuitem icon doesn't trigger the command. Here is my XAML. Is there any easy fix for this as i want to be able to click both the text and the icon for the command to run.
<MenuItem Header="Choose Shoe Colour"
ItemsSource="{Binding DataContext.ShoeModels, Source={x:Reference sItemControl}}"
Command="{Binding DataContext.ChooseShoe_Click, Source={x:Reference sItemControl}}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding ShoeColour}"
Command="{Binding DataContext.ChooseShoe_Click, Source={x:Reference sItemControl}}"
CommandParameter="{Binding ShoeId}">
<MenuItem.Icon>
<Ellipse Fill="{Binding ShoeId, Converter={StaticResource ShoeIdToColorConverter}}"/>
</MenuItem.Icon>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>

Related

MenuItem within MenuItem not using all available space

I have a menuitem that contains a datatemplate of a menuitem. Problem is the menuitem within that is not taking up all the available space on the right. Is there any way I can fix this?
<MenuItem Header="Test" ItemsSource="{Binding DataContext.Test, Source={x:Reference TestControl}}"
Command="{Binding DataContext.Test_Click, Source={x:Reference TestControl}}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding TestName}"
Command="{Binding DataContext.Test_Click, Source={x:Reference TestControl}}"
CommandParameter="{Binding TestId}">
<MenuItem.Icon>
<Ellipse Fill="{Binding TestId, Converter={StaticResource TestConverter}}"/>
</MenuItem.Icon>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
What you are observing is the built-in column spacing of the default MenuItem's ControlTemplate.
Highlighting the culprit below:
These column definitions are used to show any keyboard shortcuts that you may have for the menu item, as well as some hardcoded column padding of 13 (why? I have no idea).
So to answer your question, if you want to take up the available space on the right, you will need to override the MenuItem's Template with a ControlTemplate of your own that does not include these last two column definitions.

context menu for removing items in listview

I have a ListView which displays a list of string values. I want to add a context menu entry for each item in the list to remove the selected item. My XAML looks like this:
<ListView x:Name="itemsListView" ItemsSource="{Binding MyItems}">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove"
Command="{Binding RemoveItem}"
CommandParameter="{Binding ElementName=itemsListView, Path=SelectedItem}" />
</ContextMenu>
</ListView.ContextMenu>
</ListView>
The problem is that the CommandParameter value is always null. I've added an additional button to remove the selected item to check if my command works. The button has exactly the same binding and removing items via the button works. The button looks like this:
<Button Content="Remove selected item"
Command="{Binding RemoveItem}"
CommandParameter="{Binding ElementName=itemsListView, Path=SelectedItem}"/>
The command looks like this:
private ICommand _removeItem;
public ICommand RemoveItem
{
get { return _removeItem ?? (_removeItem = new RelayCommand(p => RemoveItemCommand((string)p))); }
}
private void RemoveItemCommand(string item)
{
if(!string.IsNullOrEmpty(item))
MyItems.Remove(item);
}
Any ideas why the selected item is null when opening the context menu? Maybe a focus problem of the listview?
H.B. is right. but you can also use RelativeSource Binding
<ListView x:Name="itemsListView" ItemsSource="{Binding MyItems}">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove"
Command="{Binding RemoveItem}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
</ContextMenu>
</ListView.ContextMenu>
</ListView>
ContextMenus are disconnected, you cannot use ElementName bindings. One workaround would be using Binding.Source and x:Reference which requires you to extract parts that use it to be in the resources (due to cyclical dependency errors). You can just put the whole context menu there.
An example:
<ListBox Name="lb" Height="200">
<ListBox.Resources>
<ContextMenu x:Key="cm">
<MenuItem Header="{Binding ActualHeight, Source={x:Reference lb}}" />
</ContextMenu>
</ListBox.Resources>
<ListBox.ContextMenu>
<StaticResource ResourceKey="cm" />
</ListBox.ContextMenu>
</ListBox>
This work for me CommandParameter="{Binding}"

ContextMenu items Visibility

I have some ContextMenu With some menuItems.
One of the menuItems is "Add Item...". when the user will selects this item, he should see submenu with list of available items;
here is description of my contextMenu:
Add Item
Item 1
Item 2
Item 3
Item 4
Delete
Copy
the ItemsSource of 'Add Item' menuItem is binded to some observable collection. Each model in the collecion has 'Name' and 'IsEnabled' (I have converter which convert bool to visibility). Everything works fine except the fact that the items which has 'IsEnable' = false, are not visible, but I can see there space.
for example: let say that Item 3 has IsEnable = false:
Add Item
Item 1
Item 2
Item 4
My bool2Vis converter return 'Collapsed' in case of false value.
Whay I'm doing wrong?
Here is the ContextMenu Code:
<ContextMenu x:Key="mainContextMenu" DataContext="{Binding Source={x:Static fw:UIMainManager.Instance},Path=layoutManager}">
<MenuItem Header="Add Item" Name="addItemMenu" ItemsSource="{Binding ControlBoxItems}" >
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding ControlName}" Visibility="{Binding IsEnabled,Converter={StaticResource boolToVisibilityConverter}}"
Command="{Binding Source={x:Static fw:ApplicationCommands.AddControlToScene}}" CommandParameter="{Binding}"/>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
<MenuItem Header="Copy" Command="{Binding Source={x:Static fw:ApplicationCommands.Copy}}" />
<MenuItem Header="Paste" Command="{Binding Source={x:Static fw:ApplicationCommands.Paste}}" />
<MenuItem Header="Cut" Command="{Binding Source={x:Static fw:ApplicationCommands.Cut}}" />
<MenuItem Header="Duplicated" Command="{Binding Source={x:Static fw:ApplicationCommands.DuplicateControl}}" />
<MenuItem Header="Delete" Command="{Binding Source={x:Static fw:ApplicationCommands.DeleteControl}}" />
</ContextMenu>
I think the MenuItem is collapsed but not the ItemContainer of MenuItem. Try this:
<MenuItem Header="Add Item" Name="addItemMenu" ItemsSource="{Binding ControlBoxItems}">
<MenuItem.ItemContainerStyle>
<Style>
<Setter Property="Visibility" Value="{Binding IsEnabled, Converter={StaticResource boolToVisibilityConverter}}" />
</Style>
</MenuItem.ItemContainerStyle>
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding ControlName}"
Command="{Binding Source={x:Static fw:ApplicationCommands.AddControlToScene}}"
CommandParameter="{Binding}" />
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>

XAML and Binding Submenu items in a ContextMenu?

I have a ContextMenu defined on a Datagrid but want to bind submenu items to a collection on my viewmodel. Can anybody suggest how this should be done?
The following is a simple example of what I'm trying to achieve, BUT I want "Test1", "Test2" to come from a collection on my viewmodel, not hardcoded. I know how to bind my collection to the whole ContextMenu, but not how to bind it to just the one submenu...
<ContextMenu>
<MenuItem Header="Add to">
<MenuItem Header="Test1" />
<MenuItem Header="Test2" />
</MenuItem>
<MenuItem Header="Remove from All" />
</ContextMenu>
I'm using 3.5 SP1 and the WPF Toolkit.
Guess I should have experimented more. Turns out this was relatively simple:
<my:DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Add to" ItemsSource="{Binding MyItems}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem CommandTarget="{Binding}" Click="AddClick">
<MenuItem.Header>
<TextBlock>
<TextBlock.Text><Binding StringFormat="Add to {0}" /></TextBlock.Text>
</TextBlock>
</MenuItem.Header>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
<MenuItem Header="Remove from All" />
</ContextMenu>
</my:DataGrid.ContextMenu>
There is a bug when using MenuItem.ItemTemplate. The color when do mouse over on the sub menu make user misunderstand that they can click to select the menu but it doesn't work for all area even if it's highlighted. See the picture
Then I used this code instead and it worked fine for me.
<ContextMenu>
<MenuItem Header="Add to" ItemsSource="{Binding MyItems}"
DisplayMemberPath="{Binding ItemName}">
<MenuItem.ItemContainerStyle>
<Style>
<EventSetter Event="MenuItem.Click" Handler="Menu_Click"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
<MenuItem Header="Remove from All" />
</ContextMenu>

Bind Command for MenuItem in DataTemplate without Tag

I want to bind a command in my ViewModel to a menuItem which is in DataTemplate. I can do that with using Tag. Is there any method which can do the same task but without using tag.
<Window.Resources>
<DataTemplate x:Key="StudentListBoxItemTemplate">
<StackPanel Tag="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}">
<TextBlock Text="{Binding Name}"/>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Trigger" Command="{Binding PlacementTarget.Tag.TriggerCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ListBox
ItemsSource="{Binding StudentList}"
ItemTemplate="{StaticResource StudentListBoxItemTemplate}">
</ListBox>
</StackPanel>
My ViewModel
public class MainViewModel {
public ICommand TriggerCommand { ... }
public ObservableList<Student> StudentList { ... }
}
With your current design, you need to get from the ContextMenu through the StackPanel and back to the DataContext of the containing ListBox. What makes this awkward is that the DataContext of the StackPanel is already narrowed down to a particular student.
There are at least two ways to make this easier:
Provide a TriggerCommand property in Student so the command is right there where you need it
Provide a Parent property in the Student to escape the narrowed scope
You can try to add click event to the menuItem like following
<Menu Style="{StaticResource bellRingersFontStyle}" Height="23" Name="menu1" Width="Auto" DockPanel.Dock="Top" VerticalAlignment="Top">
<MenuItem Header="_File">
<MenuItem Header="_New Member" Name="newMember" Click="newMember_Click" >
<MenuItem.Icon>
<Image Source="Face.bmp" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="_Save Member Details" Name="saveMember" IsEnabled="False" Click="saveMember_Click">
<MenuItem.Icon>
<Image Source="Note.bmp" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="E_xit" Name="exit" Click="exit_Click" />
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_About Middleshire Bell Ringers" Name="about" Click="about_Click" >
<MenuItem.Icon>
<Image Source="Ring.bmp" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
Try binding the command to Click. My VS is down so can't check at this moment.
One way would be to get the context menu collection presentation defined in your viewmodel, which will contain the header string and command action (maybe with predicate).
The viewmodel creates an observable collection of the contextmenu items and the view binds that to ContextMenu itemssource and sets the displaymember path to header string.

Resources