WPF MenuItem not filling available ContextMenu space - c#

I'm having a weird problem with a simple ContextMenu using MahApps.Metro without any additional styling. When moving the cursor on top of the text or slightly around it, there is no problem. But when moving it further away, still inside the ContextMenu bounds, the Cursor is no longer on top of the MenuItem. Clicking now also doesn't result in any action at all besides closing the ContextMenu.
<ContextMenu ItemsSource="{Binding ContextItems}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Text}" Command="{Binding Command}"/>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
What am I doing wrong? Why doesn't the MenuItem use the available space?

If your ContextItems holds a collection with viewmodels then I think this could help you (not tested):
<ContextMenu ItemsSource="{Binding ContextItems}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Text}" />
<Setter Property="Command" Value="{Binding Command}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
Command and Text should be the properties on the viewmodel object.

I havent used MahApps.Metro . Though you can override the template like this
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Text}" Command="{Binding Command}"/>
<MenuItem.Template>
<ControlTemplate>
<ContentPresenter Content="{Binding Header,RelativeSource={RelativeSource TemplatedParent}}">
</ContentPresenter>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
</DataTemplate>
</ContextMenu.ItemTemplate>
I hope this will help.

Related

WPF Context Menu Click event works in one place, not in another

I have the following XAML that produces a ListBox where each item contains another ListBox inside an Expander, and I have defined PageContextMenu as the context menu for the top level list and FrameContextMenu for the lower level list.
The problem: Both are displayed correctly, but click events are only working on the top level context menu and not the lower level context menu. For example, clicking on Delete Selected in PageContextMenu correctly invokes the associated handler, but clicking on Delete Selected Frame(s) in FrameContextMenu does NOT fire the associated handler. I'm not seeing any indication of an error, and even if I put a breakpoint in ContextDeleteFrames_Click it doesn't get hit. It's as if there's no handler associated with that menu entry at all.
I've looked at a number of other questions relating to context menus not working, but none seemed applicable. Is there some problem with the two list boxes being nested?
XAML:
<ListBox Name="PageListBox" ItemsSource="{Binding CurrentPack.Pages}" HorizontalAlignment="Stretch" SelectionMode="Extended">
<ListBox.Resources>
<ContextMenu x:Key="PageContextMenu">
<MenuItem Header="_Add" Name="ContextAddAddPage"/>
<MenuItem Header="_Edit" Name="ContextEditPage"/>
<MenuItem Header="_Delete Selected" Name="ContextDeletePage" Click="ContextDeletePage_Click"/>
</ContextMenu>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContextMenu" Value="{StaticResource PageContextMenu}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate >
<Border BorderThickness="2" BorderBrush="White" HorizontalAlignment="Stretch">
<StackPanel HorizontalAlignment="Stretch">
<Label Content="{Binding PresentationName}"/>
<Expander VerticalAlignment="Top" HorizontalAlignment="Stretch">
<Expander.Header>
<Label Content="{Binding FrameStatusText}"/>
</Expander.Header>
<ListBox Name="FrameListBox" ItemsSource="{Binding Frames}" HorizontalAlignment="Stretch" SelectionMode="Extended">
<ListBox.Resources>
<ContextMenu x:Key="FrameContextMenu">
<MenuItem Header="_Add Frame" Name="ContextAddFrame"/>
<MenuItem Header="_Edit Frame" Name="ContextEditFrame"/>
<MenuItem Header="_Delete Selected Frame(s)" Name="ContextDeleteFrames" Click="ContextDeleteFrames_Click"/>
<MenuItem Header="Show _Preview" Name="ContextShowPreview" Click="ContextShowPreview_Click"/>
</ContextMenu>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContextMenu" Value="{StaticResource FrameContextMenu}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding PresentationName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
Code Behind:
private void ContextDeletePage_Click(object sender, RoutedEventArgs e)
{ //this works
Workspace.Content.DeleteSelectedPages();
}
private void ContextDeleteFrames_Click(object sender, RoutedEventArgs e)
{ //this doesn't!
Workspace.Content.DeleteSelectedFrames();
}
Don't use events in a DataTemplate. They won't work.
Either move your second context menu from the DataTemplate's resources into the PageListBox resources like this:
<ListBox Name="PageListBox">
<ListBox.Resources>
<!-- ... other resources... -->
<ContextMenu x:Key="FrameContextMenu">
<MenuItem Header="_Add Frame" Name="ContextAddFrame"/>
<MenuItem Header="_Edit Frame" Name="ContextEditFrame"/>
<MenuItem Header="_Delete Selected Frame(s)" Click="ContextDeleteFrames_Click"/>
<MenuItem Header="Show _Preview" Name="ContextShowPreview" Click="ContextShowPreview_Click"/>
</ContextMenu>
</ListBox.Resources>
</ListBox>
...or use commands instead of events:
<MenuItem Header="_Delete Selected Frame(s)" Command="{Binding DeleteFrameCommand}"/>
where DeleteFrameCommand is a property of type ICommand or RoutedCommand.
If you want to use commands, you should be aware that a context menu is not in the visual tree of its PlacementTarget, so you'll have to use some helpers to make the bindings work (a binding proxy or PlacementTarget.Tag property etc.)

How to set 2 color background to a TreeView (WPF)

I want to set two color background to a custom tree view (wpf). You can set this propriety in a DataGrid. I could not figure out a way to do it for a tree view.
I also want to set the selection of a element to be as big as the cell.
<TreeView Grid.Row="2" Name="TreeView" DataContext="{Binding Path=TreeModel}" ItemsSource="{Binding TreeItems}" SelectedItemChanged="TreeView_OnSelectedItemChanged">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:NodeViewModel}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding NameNode}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Add" Command="{Binding AddMachinePart_Command}"/>
<MenuItem Header="Remove" Command="{Binding RemoveMachinePart_Command}" IsEnabled="{Binding IsModule}"/>
<MenuItem Header="Edit" Command="{Binding EditMachinePart_Command}" IsEnabled="{Binding IsModule}"/>
<Separator></Separator>
<MenuItem Header="Copy path" Command="{Binding CopyPath_Command}" IsEnabled="{Binding IsModule}"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Edit:
When using the solution from
https://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.alternationindex(v=vs.110).aspx suggested #jschroedl
It would be ideal to be as large as the tree view grid like shown in picture below:
You will probably want to use ItemsControl.AlternationIndex in a Style to control how many colors to cycle (2 in your case).
MSDN Docs for ItemsControl.AlternationIndex has an example with ListBox which you can probably adapt to TreeView as well.

WPF Application - <Ellipse.InputBindings> - <MouseBinding>

Hi I am new to WPF Development and run into a problem Regarding Mouse Binding of an Ellipse which was created with Item Controls Trough Data Binding. This is the source code. My Problem is that the "CLoadModelFromDisk" Binding is not executed. In another context the Command works without any problems.
<ItemsControl ItemsSource="{Binding JointsModelPartView}" Grid.Row="1" Grid.Column="1">
<ItemsControl.ItemContainerStyle>
<Style TargetType="FrameworkElement">
<Setter Property="Canvas.Left" Value="{Binding posx1}" />
<Setter Property="Canvas.Top" Value="{Binding posy1}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="Point">
<Ellipse Fill="AntiqueWhite"
Stroke="Black"
Width="10"
Height="10"
Margin="-5,-5,5,5"
>
<Ellipse.InputBindings>
<MouseBinding
Command="{Binding CLoadModelFromDisk}"
Gesture="LeftClick"
/>
</Ellipse.InputBindings>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
It would be really nice if somebody could help me with this problem.
This is the code for the context menu which does not work with your solution. Do you have any idea why?
<Ellipse.ContextMenu>
<ContextMenu ItemsSource="{Binding DataContext.ContextActionsView, RelativeSource={RelativeSource AncestorType=ItemsControl}}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Name}"/>
<Setter Property="Command" Value="{Binding RCommand}"/>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Ellipse.ContextMenu>
I already tried to set the Relative Source to the Header and Command but that also does not worked.
In your DataTemplate, the DataContext will be the item displayed in the template -- one of the items in JointsModelPartView. Do those items have a property of type ICommand named CLoadModelFromDisk?
My guess is that they don't, and CLoadModelFromDisk is a member of the same viewmodel as JointsModelPartView. In that case, you need to bind not to the list item, but to the parent viewmodel to which the property actually belongs. That'll be the DataContext of the ItemsControl -- it must be, since the ItemsControl is able to bind to JointsModelPartView.
Try this:
<MouseBinding
Command="{Binding DataContext.CLoadModelFromDisk, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
Gesture="LeftClick"
/>

Can I set ToolBar items in XAML?

Feel free to suggest an alternate approach to my problem if this isn't the best way to go about it.
I have a ToolBarTray and a TreeView. The tree has 2 items that are Concrete1 and Concrete2 classes respectively. I want the toolbar to have a different menu depending on which type of item is selected in the tree.
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<ToolBar.Style>
<Style TargetType="{x:Type ToolBar}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tree, Path=SelectedItem, Converter={StaticResource convert}}" Value="{x:Type root:Concrete1}">
<!--what do i do here??-->
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tree, Path=SelectedItem, Converter={StaticResource convert}}" Value="{x:Type root:Concrete2}">
<!--what do i do here??-->
</DataTrigger>
</Style.Triggers>
</Style>
</ToolBar.Style>
<ToolBar.Resources>
<Menu x:Key="awd">
<MenuItem Header="AWD"></MenuItem>
</Menu>
<Menu x:Key="dwa">
<MenuItem Header="DWA"></MenuItem>
</Menu>
</ToolBar.Resources>
</ToolBar>
</ToolBarTray>
<TreeView x:Name="tree" ItemsSource="{Binding Families}"></TreeView>
I've gotten as far as being able to set any regular property (background, etc) of the toolbar depending on which item is selected. I don't know how to proceed to add specific Menus to the toolbar.
I think I've figured it out. I've only done this with a ContextMenu and outside of a style trigger but I imagine it would be the same principle.
<TreeView>
<TreeView.ContextMenu>
<ContextMenu>
<StaticResourceExtension ResourceKey="myMenuItem"></StaticResourceExtension>
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>

Context sub menu with items source and additional items

I have a context menu in wpf. One of the items in the menu has a sub menu that gets populated from the ItemsSource of the header menu item. This sub menu is a list of commands that can be sent to another portion of the app. The list is basically a mru list restricted to 10 items. I want to add a separator and then a "More" option below the list of 10 items so the user can see the entire list of available commands. I can't seem to figure out how to add these extra items. I can get the list to populate dynamically from the ItemsSource of the parent menu item but I can't seem to figure out how to add the additional items to the bottom of the child menu. I don't want to put them in the items source and the "More" item needs to have its own command.
<MenuItem x:Name="ExecuteCommandMenuItem" Height="22" Style="{StaticResource RightClickMenuItemStyle}"
ItemsSource="{Binding Path=PanelCommands}">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Panel Command" HorizontalAlignment="Left" Width="100"/>
</StackPanel>
</MenuItem.Header>
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem" BasedOn="{StaticResource RightClickMenuItemStyle}">
<Setter Property="MenuItem.Header" Value="{Binding}" />
<Setter Property="MenuItem.Command" Value="CommonCommands:CommandRepository.ExecutePanelCommand" />
<Setter Property="MenuItem.CommandParameter">
<Setter.Value>
<MultiBinding Converter="{CommonConverter:PanelCommandArgsConverter}">
<MultiBinding.Bindings>
<Binding Path="DataContext" RelativeSource="{RelativeSource FindAncestor,
AncestorType={x:Type ContextMenu}}"/>
<Binding Path="Command" />
</MultiBinding.Bindings>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
Thanks.
<DataGrid x:Class="UICCNET.BaseControls.UserControls.BaseDataGrid"
Tag="{Binding RelativeSource={RelativeSource Self}, Path=Columns}">
<DataGrid.ContextMenu>
<ContextMenu Tag="{Binding RelativeSource={RelativeSource Self},Path=PlacementTarget.Tag}">
<MenuItem Header="Колонки">
<MenuItem >
<MenuItem.Template>
<ControlTemplate>
<ListBox Name="MyComboBox" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}},Path=Tag}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Visibility, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter1}}" Content="{Binding Path=Header}"></CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
</MenuItem>
<MenuItem Header="Друк"></MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
I dont think you can because it's bound to a source. So either add them to the source OR use a templateselector and do your logic in there. Define a normal template and then a "more" template.
Or, you can do some control nesting like
<menu>
<stackpanel>
<Menu Items>
</menu Items>
<break />
<Button>More</button>
</stackpanel>
</menu>
Sorry this is just off the top of my head. Can you post your XAML?

Categories

Resources