Silverlight で ContextMenu を使ってみる

Silverlight 4 Tools の日本語版がようやく公開されたので、前から気になっていた Silverliht Tools の ContextMenu を試してみた。

使い方は WPF の ContextMenu とたいして変わらない。メニューをクリックしたときに実行する処理を Click イベントハンドラか Command で指定できるところも同じ。

MainPage.xaml
<UserControl x:Class="ContextMenuSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:cinput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <StackPanel x:Name="LayoutRoot" Background="White">
        <!--Clickイベントを使ったサンプル-->
        <TextBox x:Name="eventTextBox" Margin="20">
            <cinput:ContextMenuService.ContextMenu>
                <cinput:ContextMenu>
                    <cinput:MenuItem Header="コピー" Click="CopyMenuClick"/>
                    <cinput:MenuItem Header="貼り付け" Click="PasteMenuClick"/>
                    <cinput:MenuItem Header="切り取り" Click="CutMenuClick"/>
                </cinput:ContextMenu>
            </cinput:ContextMenuService.ContextMenu>
        </TextBox>
        <!--Commandを使ったサンプル-->
        <TextBox x:Name="commandTextBox" Margin="20">
            <cinput:ContextMenuService.ContextMenu>
                <cinput:ContextMenu>
                    <cinput:MenuItem Header="コピー" Command="{Binding Path=CopyCommand}"/>
                    <cinput:MenuItem Header="貼り付け" Command="{Binding Path=PasteCommand}"/>
                    <cinput:MenuItem Header="切り取り" Command="{Binding Path=CutCommand}"/>
                </cinput:ContextMenu>
            </cinput:ContextMenuService.ContextMenu>
        </TextBox>
    </StackPanel>
</UserControl>
MainPage.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace ContextMenuSample
{
    public class DelegateCommand : ICommand
    {
        private Action<object> execute;
        private Func<object, bool> canExecute;

        public DelegateCommand(Action<object> execute)
            : this(execute, _ => true)
        {
        }

        public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public bool CanExecute(object p)
        {
            return this.canExecute(p);
        }

        public void Execute(object p)
        {
            this.execute(p);
        }

        // とりあえず実装しただけ
        public event EventHandler CanExecuteChanged;
    }

    public partial class MainPage : UserControl
    {
        private string eventText;
        private string commandText;
        public ICommand CopyCommand { get; private set; }
        public ICommand CutCommand { get; private set; }
        public ICommand PasteCommand { get; private set; }

        public MainPage()
        {
            InitializeComponent();

            this.CopyCommand = new DelegateCommand(CopyCommandExecute);
            this.CutCommand = new DelegateCommand(CutCommandExecute);
            this.PasteCommand = new DelegateCommand(PasteCommandExecute);
            this.DataContext=this;
        }

        private void CopyMenuClick(object sender, RoutedEventArgs e)
        {
            this.eventText = this.eventTextBox.Text;
        }

        private void PasteMenuClick(object sender, RoutedEventArgs e)
        {
            if (this.eventText != null)
                this.eventTextBox.Text = eventText;
        }

        private void CutMenuClick(object sender, RoutedEventArgs e)
        {
            this.eventText = this.eventTextBox.Text;
            this.eventTextBox.Text = "";
        }

        private void CopyCommandExecute(object p)
        {
            this.commandText = this.commandTextBox.Text;
        }

        private void CutCommandExecute(object p)
        {
            this.commandText = this.commandTextBox.Text;
            this.commandTextBox.Text = "";
        }

        private void PasteCommandExecute(object p)
        {
            if(this.commandText!=null)
                this.commandTextBox.Text = this.commandText;
        }
    }
}
実行画面

f:id:griefworker:20100611162528j:image

ContextMenu は右クリックで表示できるけど、テキストの選択状態が解除されてしまう。まだ編集機能には使えそうにない。

ToolBar や MenuBar のような、ドロップダウンメニューを表示するコントロールを自作するのがだいぶ楽になると思う。Silverlight に標準で含まれているのが一番いいんだけど、ね。

今回作成したプロジェクト

下のリンクからダウンロードできます。