Contextual Menu On Mouse Hover in WPF
From Wikipedia
A context menu (also called contextual, shortcut, and popup or pop-up menu) is a menu in a graphical user interface (GUI) that appears upon user interaction, such as a right-click mouse operation. A context menu offers a limited set of choices that are available in the current state, or context, of the operating system or application. Usually the available choices are actions related to the selected object.
The purpose of this post is to show how you can create a modern contextual Menu that can enhance user experience.
Xaml Code:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Width="525"
Height="350">
<Grid>
<Grid.Resources>
<Style x:Key="btnWithoutBrd" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel Name="stckPanel" Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter Name="fstImage"
Width="12"
Height="12"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="fstImage" Property="Width" Value="16" />
<Setter TargetName="fstImage" Property="Height" Value="16" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<DockPanel Name="dkpMain"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<ListBox Name="lbxNewEntries"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Background="Transparent"
BorderBrush="LightGray"
BorderThickness="1"
ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Name="mainBrdItem"
Margin="0"
BorderBrush="LightGray"
BorderThickness="0,0,0,1"
Padding="1">
<Border Name="brdSelectedItem"
Margin="2"
BorderBrush="LightGray"
BorderThickness="0"
CornerRadius="2"
Padding="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="4"
DataContext="{Binding}">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<TextBlock Name="tbkDescr"
Grid.Column="0"
Cursor="Hand"
FontFamily="Calibri"
FontSize="12"
FontWeight="Bold"
Foreground="#FF5681C4"
Text="{Binding Path=Name}" />
<Button Name="btnMoreDetails"
Grid.Row="0"
Grid.Column="1"
Margin="0,2,0,0"
Click="BtnMoreDetails_OnClick"
DockPanel.Dock="Right"
Style="{StaticResource btnWithoutBrd}"
Tag="{Binding Path=Description}"
Visibility="Hidden">
<Button.Content>
<Image Source="images/more.png" Stretch="Fill" />
</Button.Content>
</Button>
<Button Name="btnEdit"
Grid.Row="0"
Grid.Column="2"
Margin="0,2,0,0"
Click="BtnMoreDetails_OnClick"
DockPanel.Dock="Right"
Style="{StaticResource btnWithoutBrd}"
Tag="{Binding Path=Description}"
Visibility="Hidden">
<Button.Content>
<Image Source="images/edit.png" Stretch="Fill" />
</Button.Content>
</Button>
</Grid>
</Grid>
</Border>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="True">
<Setter TargetName="brdSelectedItem" Property="Background" Value="#60A3C1F4" />
<Setter TargetName="brdSelectedItem" Property="BorderThickness" Value="1" />
<Setter TargetName="btnMoreDetails" Property="Visibility" Value="Visible" />
<Setter TargetName="btnEdit" Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsMouseOver}" Value="True">
<Setter TargetName="brdSelectedItem" Property="Background" Value="#AADDDDDD" />
<Setter TargetName="btnMoreDetails" Property="Visibility" Value="Visible" />
<Setter TargetName="btnEdit" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Resources>
<!-- Style used if item is selected and listbox has keyboard focus -->
<Style x:Key="NoFocusVisualStyle" TargetType="Control">
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
<!-- Apply this style -->
<Style x:Key="{x:Type ListBoxItem}" TargetType="ListBoxItem">
<Setter Property="FocusVisualStyle" Value="{StaticResource NoFocusVisualStyle}" />
</Style>
<!-- Color used if item is selected and listbox has focus -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<!-- Color used if item is selected and listbox does not have focus -->
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
<!-- Font color used if item is selected and listbox has focus -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
</ListBox.Resources>
</ListBox>
</DockPanel>
</Grid>
</Window>
Code .CS
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//just for a demo purpose Mvvm created like this
public ObservableCollection<Article> Mvvm = new ObservableCollection<Article>();
public MainWindow()
{
InitializeComponent();
this.DataContext = Mvvm;
for (int i = 0; i < 10; i++)
{
Mvvm.Add(new Article() { Name = "Article number" + i, Description = "Lorem ipsum dolor sit amet :) for article " + i });
}
}
private void BtnMoreDetails_OnClick(object sender, RoutedEventArgs e)
{
MessageBox.Show(((sender) as Button).Tag.ToString());
}
}
public class Article : INotifyPropertyChanged
{
public string Name
{
get { return _name; }
set
{
if (_name!=value)
{
_name = value;
OnPropertyChanged("Name");
}
}
}
public string Description
{
get { return _descr; }
set
{
if (_descr!=value)
{
_descr = value;
OnPropertyChanged("Description");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string prop)
{
if (PropertyChanged!=null)
{
PropertyChanged(this,new PropertyChangedEventArgs(prop));
}
}
private string _name;
private string _descr;
}
}
