Customizing Context Menu in WPF - wpf

I have a project here where I require customizing the context menu in my WPF application in which a button would be placed at the bottom of all the menuitems.
However, if I were to add the button through the XAML, it would appear as another item in the collection in the context menu and the mouse-over highlight would act on it.
I would like to have the context menu tuned to a grid-like style whereby I could customize the style underneath it.
Any idea how I can achieve this (preferably in the XAML)?

It's actually pretty straightforward in the XAML.
Just define it under the element for which you want to have the context menu.
<Border>
<Border.ContextMenu>
<ContextMenu>
<ContextMenu.Template>
<ControlTemplate>
<Grid>
<!--Put anything you want in here.-->
</Grid>
</ControlTemplate>
</ContextMenu.Template>
</ContextMenu>
</Border.ContextMenu>
</Border>

For your menu item style with the button in the item you can use the following code:
Note - Adding items to the Header will keep it in the same MenuItem, but if added to the MenuItem only it will be regarded as a new MenuItem.
<ContextMenu>
<ContextMenu.Items>
<MenuItem>
<MenuItem.Header>
<StackPanel>
<TextBlock Text="Item 1"/>
<Button Content="Button 1" Margin="5"/>
</StackPanel>
</MenuItem.Header>
</MenuItem>
<MenuItem>
<MenuItem.Header>
<StackPanel>
<TextBlock Text="Item 2"/>
<Button Content="Button 2" Margin="5"/>
</StackPanel>
</MenuItem.Header>
</MenuItem>
</ContextMenu.Items>
</ContextMenu>
This will be the resulting ContextMenu:
From there you can style the MenuItem or Button etc.
Hope it helps!

You can start with the example style/template (from here) for ContextMenu and adjust it to your needs.
<Style TargetType="{x:Type ContextMenu}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Grid.IsSharedSizeScope" Value="true" />
<Setter Property="HasDropShadow" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContextMenu}">
<Border x:Name="Border"
Background="{StaticResource MenuPopupBrush}"
BorderThickness="1">
<Border.BorderBrush>
<SolidColorBrush Color="{StaticResource BorderMediumColor}" />
</Border.BorderBrush>
<StackPanel IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Cycle" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" Value="true">
<Setter TargetName="Border" Property="Padding" Value="0,3,0,3" />
<Setter TargetName="Border" Property="CornerRadius" Value="4" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Related

Button opacity does not apply

So I am trying to make a button template. However, I cannot get background opacity to work, despite having implemented it exactly the same way as for the parent container (where it works). If I completely remove the background setter from the template, then it correctly inherits from the parent container, but then only the text of the button is clickable (and not the surroundings), so it appears that I am required to set the background for the button itself.
How do I make the background of the buttons identical the the back ground of the parent control, without losing the ability to click the entire button (and not just the text)?
My XAML looks like this:
<Grid DockPanel.Dock="Top">
<!-- This is what I also want for my buttons-->
<Grid.Background>
<SolidColorBrush Color="Black" Opacity="0.8" />
</Grid.Background>
<UniformGrid
HorizontalAlignment="Center"
Columns="4"
Width="800"
Height="50">
<UniformGrid.Resources>
<Style TargetType="Button">
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="12" />
<!-- And this is how I try to achieve it -->
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Black" Opacity="0.8" />
</Setter.Value>
</Setter>
<Setter Property="FontWeight" Value="Medium" />
<Setter Property="Foreground" Value="White" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border BorderThickness="0" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="TextBlock.Foreground" Value="Silver"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UniformGrid.Resources>
<Button
Content="{Binding ValuationButtonText}"
Command="{Binding NavigationCommand}"
CommandParameter="valuation"
Foreground="{Binding ValuationButtonForeground}" />
<Button
Content="Opdater Leasing Core"
Command="{Binding NavigationCommand}"
CommandParameter="leasingCore"
Foreground="{Binding LeasingCoreButtonForeground}" />
<Button
Content="Opdater Motorregister"
Command="{Binding NavigationCommand}"
CommandParameter="motorregister"
Foreground="{Binding MotorregisterButtonForeground}" />
<Button
Content="Behandles Manuelt"
Command="{Binding NavigationCommand}"
CommandParameter="manualProcessing"
Foreground="{Binding ManualProcessingButtonForeground}" />
</UniformGrid>
</Grid>
I actually found a solution. It is rather silly, but it works.
You replace the <Setter> background properties with this:
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent" Opacity="1" />
</Setter.Value>
</Setter>
By having transparent background, the entire button becomes clickable, but the actual color (and opacity) of the button, is inherited from the parent container.

WPF apply triggers to listview items to change background

I am trying to create a sort of left menu for navigation inside the desktopapplication. My idea is to use Buttons as Listview items which should behave in this way: when i hover with the mouseover them theri background should change color (becomes darkCyan) and when i click one its background color should change persistently (to darkCyan) until i click on another button of the list. The problem is that i am using a the DataTemplate property to specify how the buttons should look like and I am tryin to apply the triggers to change the background color on the ControlTemplate of the ListView. The result is that sometimes the background color changes but the command related to the button is not fired other times the contrary. I think that I am doing the things in the wrong element of the tree view, but I don't have enough knowledge of the tree view so I am not understanding what I am doing wrong. Here is the code of the XAML in which i define the styles for the Buttons and the ListView
<Window.Resources>
<DataTemplate DataType="{x:Type viewModels:TripViewModel}">
<views:TripView />
</DataTemplate>
<Style TargetType="{x:Type Button}">
<Setter Property="Height"
Value="50" />
<Setter Property="Background"
Value="#555D6F" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border>
<Grid Background="Transparent">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border BorderBrush="Transparent"
BorderThickness="0"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="DarkCyan" />
</Trigger>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Background"
Value="DarkCyan" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
And here is the code in which I create the ListView
<ListView Name="MenuButtons"
ItemsSource="{Binding PageViewModels}"
Background="Transparent"
IsSynchronizedWithCurrentItem="True">
<ListView.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
Margin="0" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Anyone can help?
Thanks
I have solved the issue by using a ListBox instead of a ListView and setting the ItemContainer to be a button in the following way
<ListBox.ItemTemplate>
<ItemContainerTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
Margin="0" />
</ItemContainerTemplate>
</ListBox.ItemTemplate>

WPF Flat button style with image and text inside even when hover

I'm trying to create a flat styled wpf button. Like on the picture below (the log-out button). I want to have an image and text inside the button even if you hover it. But what happened is every time i try to put a hover style/effects the button turn plain blue when hover and image and text are missing.
Can anyone help me with this? Thank you!
Here's what I tried so far :
<Button Name="button_lgout">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}"></ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
<Image Source="Images/logout.png" Height="21" VerticalAlignment="Top" Margin="0,5,0,0"/>
<Label Name="lbl_lgout" Content="LOGOUT" FontSize="12" Foreground="White" FontFamily="Calibri" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,-4" Height="27" />
I think some of your code is missing, from the question. eg. the Control template does not have any visual tree. also seems like you are also talking about some triggers, mouse hover etc. please include them too if necessary
however to create a plain button with any arbitrary content you may use this example
<Button Name="button_lgout">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter TextElement.Foreground="{TemplateBinding Foreground}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
<StackPanel>
<Image Source="Images/logout.png" Height="21" HorizontalAlignment="Center" Margin="0,5,0,0"/>
<Label Name="lbl_lgout" Content="LOGOUT" FontSize="12" Foreground="White" FontFamily="Calibri" HorizontalAlignment="Center" Height="27" />
</StackPanel>
</Button>
you may also try to set <StackPanel HorizontalContentAlignment="Center"> and see if this can replace HorizontalAlignment="Center" from sub items. also Foreground="White" is redundant as specified in the button style, you may safely remove either of them
Enable hover effect
as requested here is how you can implement a simple hover effect. assuming that the container of the button has the desired color, this effect will darken the background color
<Button Name="button_lgout" HorizontalAlignment="Center" VerticalAlignment="Top">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Foreground"
Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter TextElement.Foreground="{TemplateBinding Foreground}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Background"
Value="#2000" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
<StackPanel>
<Image Source="desert.jpg"
Height="21"
HorizontalAlignment="Center"
Margin="0,5,0,0" />
<Label Name="lbl_lgout"
Content="LOGOUT"
FontSize="12"
Foreground="White"
FontFamily="Calibri"
HorizontalAlignment="Center"
Height="27" />
</StackPanel>
</Button>
I have added <Setter Property="Background" Value="Transparent" />. this is necessary for TemplateBinding to work with the setters in triggers, these setter can also be used with TargetName but former approach will also help to define a base color if needed. I also added a control template trigger for IsMouseOver to apply the effect
if you want to increase the darkness, increase the alpha component 2 in Value="#2000". possible hex values are 0 to F where is 0 is least dark and F is most dark
You need to add ContentPresenter in button template and move the image and label inside some panel and add them as child of button:
<Button Name="button_lgout">
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter/>
</ControlTemplate>
</Button.Template>
<Grid>
<Image Source="Images/logout.png" Height="21" VerticalAlignment="Top"
Margin="0,5,0,0"/>
<Label Name="lbl_lgout" Content="LOGOUT" FontSize="12" Foreground="White"
FontFamily="Calibri" VerticalAlignment="Bottom"
HorizontalAlignment="Center" Margin="0,0,0,-4" Height="27" />
</Grid>
</Button>

Correctly set a context menu inside of a template

I am trying to setup a control template that allows me to add a context menu to an element. Trouble is the only way I can figure out how to do it is by nesting TWO LABELS.
This is my style:
<Style x:Key="RightClickMenu" TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Label Name="RightClickElement">
<Label.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem x:Name="CopyMenuItem" Command="{Binding DataContext.OnCopyCommand}" InputGestureText="Ctrl+C" Header="Copy" />
<MenuItem x:Name="PasteMenuItem" Command="{Binding DataContext.OnPasteCommand}" InputGestureText="Ctrl+P" Header="Paste" />
</ContextMenu>
</Label.ContextMenu>
</Label>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now the only way to get this into a label is by doing:
<Expander Name="ExpanderControl" Margin="5,5,5,5">
<Expander.Header>
<Label x:Name="LabelTemplate" Style="{StaticResource RightClickMenu}" />
</Expander.Header>
</Expander>
Which means I end up with which is a bit rubbish. Plus it means I cant define this context menu for other controls!
How can I specify that my expnder header has a template. Which is just a single label?

Common Tooltip style in WPF

Can I make a tooltip style which can be applied to all tooltips for every control?
I tried this but I cant get the content (Tooltip text) in style, it is showing empty text in tooltip:
<Style TargetType="{x:Type ToolTip}" >
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="HasDropShadow" Value="True" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Placement" Value="Bottom" />
<Setter Property="VerticalOffset" Value="0" />
<Setter Property="Padding" Value="8" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}" >
<StackPanel Margin="7,1" >
<Border Background="#FFF7F7CC" CornerRadius="1" >
<TextBlock Margin="1" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Top" Text="{TemplateBinding ToolTip}"/>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
For Using this style I have to put a seperate Tooltip tag in control, eg to apply tooltip to border,
<Border>
<Border.ToolTip>
<ToolTip ToolTip="This is tooltip text" />
</Border.ToolTip>
........
.........
</Border>
but is there any way where tooltipstyle applies to all control with tooltip mentioned in same tag.
eg.
<Border BorderBrush="Transparent" Background="Transparent" Cursor="Help" ToolTip="This is Tooltip" >
.....
.....
</Border>
let me know if any further details are required.
Thanks in Anticipation.
Yes Your approach will work. But a small change is needed in the Control Template. Replace the TextBlock with ContentPresenter.
<ControlTemplate TargetType="{x:Type ToolTip}" >
<StackPanel Margin="7,1" >
<Border Background="#FFF7F7CC" CornerRadius="1" >
<ContentPresenter Margin="1" HorizontalAlignment="Center" VerticalAlignment="Top" />
</Border>
</StackPanel>
</ControlTemplate>

Resources