Tuesday, 28 August 2012

Silverlight Metro Context Menu

Here is a quick example project for creating a Silverlight Metro styled Context Menu.

Live Demo:   http://stevenhollidge.com/blog-source-code/metrocontextmenu

<Application x:Class="MetroContextMenu.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
<Application.Resources>
<Style TargetType="toolkit:ContextMenu">
<Setter Property="Background" Value="White" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="Padding" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="toolkit:ContextMenu">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="2">
<Grid>
<ItemsPresenter Margin="{TemplateBinding Padding}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style TargetType="toolkit:MenuItem">
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Padding" Value="20,2,20,2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="toolkit:MenuItem">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0"
Storyboard.TargetName="Presenter"
Storyboard.TargetProperty="Opacity"
To="0.1" />
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Unfocused" />
<VisualState x:Name="Focused">
<Storyboard>
<DoubleAnimation Duration="0"
Storyboard.TargetName="Bg"
Storyboard.TargetProperty="Opacity"
To="1" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="Bg"
Fill="#34C5EBFF"
Opacity="0"
Stroke="#8071CBF1"
StrokeThickness="1" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

<ContentPresenter x:Name="Presenter"
Margin="{TemplateBinding Padding}"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}" />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace MetroContextMenu
{
public class TextBoxCutCopyPasteContextMenuBehavior : Behavior<TextBox>
{
private readonly ContextMenu contextMenu;
private readonly MenuItem copyMenuItem;
private readonly MenuItem cutMenuItem;
private readonly MenuItem pasteMenuItem;

public TextBoxCutCopyPasteContextMenuBehavior()
{
contextMenu = new ContextMenu();

cutMenuItem = new MenuItem { Header = "Cut" };
cutMenuItem.Click += CutClick;
contextMenu.Items.Add(cutMenuItem);

copyMenuItem = new MenuItem { Header = "Copy" };
copyMenuItem.Click += CopyClick;
contextMenu.Items.Add(copyMenuItem);

pasteMenuItem = new MenuItem { Header = "Paste" };
pasteMenuItem.Click += PasteClick;
contextMenu.Items.Add(pasteMenuItem);
}

void PasteClick(object sender, RoutedEventArgs e)
{
AssociatedObject.SelectedText = Clipboard.GetText();
contextMenu.IsOpen = false;
}

void CutClick(object sender, RoutedEventArgs e)
{
Clipboard.SetText(AssociatedObject.SelectedText);
AssociatedObject.SelectedText = string.Empty;
AssociatedObject.Focus();
contextMenu.IsOpen = false;
}

void CopyClick(object sender, RoutedEventArgs e)
{
Clipboard.SetText(AssociatedObject.SelectedText);
AssociatedObject.Focus();
contextMenu.IsOpen = false;
}

protected override void OnAttached()
{
AssociatedObject.MouseRightButtonDown += AssociatedObject_MouseRightButtonDown;
AssociatedObject.MouseRightButtonUp += AssociatedObjectMouseRightButtonUp;
AssociatedObject.SetValue(ContextMenuService.ContextMenuProperty, contextMenu);
base.OnAttached();
}

void AssociatedObjectMouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
pasteMenuItem.IsEnabled = Clipboard.ContainsText();

if (string.IsNullOrEmpty(AssociatedObject.SelectedText))
{
cutMenuItem.IsEnabled = false;
copyMenuItem.IsEnabled = false;
}
else
{
cutMenuItem.IsEnabled = true;
copyMenuItem.IsEnabled = true;
}

contextMenu.IsOpen = true;
}

void AssociatedObject_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}

protected override void OnDetaching()
{
AssociatedObject.MouseRightButtonDown -= AssociatedObject_MouseRightButtonDown;
AssociatedObject.MouseRightButtonUp -= AssociatedObjectMouseRightButtonUp;
base.OnDetaching();
}
}
}

Source code:  https://github.com/stevenh77/MetroContextMenu

3 comments: