C#のメニューのイベントを1つにまとめてみた
アプリにメニューを付けると、メニューの各項目毎にClickイベントのコードを書くことになります。ですが、実は各メニュー項目が同じメソッドを引数を変えて呼び出していたりして、そうすると項目毎にClickイベントを書くのも面倒だなと思うことがあります。
ということで、各メニュー項目から同一のイベントハンドラを呼び出すようにしてみました。
目次
試してみた
Headerで識別する編
メニューには、必ずHeaderを設定します。文字表示の無いメニューをクリックさせるとか、考えられないからです。というわけで、必ず設定するHeaderを使って識別してみます。
まずXAMLでメニューを作ります。各メニュー項目(MenuItem)には、Header要素とClick要素だけを設定します。Headerには、そのメニュー項目が表示する文字列を設定します。Clickには、そのメニュー項目がクリックされたときに実行されるイベントハンドラを指定します。
下記のようにしてみました。
<Window x:Class="WpfApp1.MainWindow"
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:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200" >
<Grid>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="やりましょう">
<MenuItem Header="これ" Click="MenuItem_Click" />
<MenuItem Header="それ" Click="MenuItem_Click" />
<MenuItem Header="あれ" Click="MenuItem_Click" />
<MenuItem Header="どれ?" Click="MenuItem_Click" />
</MenuItem>
</Menu>
<TextBlock Name="textblock" />
</DockPanel>
</Grid>
</Window>
MenuItem要素には、Header属性とClick属性だけが設定されています。Click属性の設定値が、全てMenuItem_Clickになっています。
コードは下記のようにしました。MenuItemのClickイベントの中で、Headerを使って実行するコードを切り替えています。
using System.Windows;
using System.Windows.Controls;
namespace WpfApp1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem menuitem = (MenuItem)sender; // オブジェクトをMenuItemクラスのインスタンスにキャストする。
string header = menuitem.Header.ToString(); // Headerプロパティを取り出して、文字列に変換する。
switch (header) // Header文字列毎の処理
{
case "これ":
textblock.Text = textblock.Text + header + "\r\n";
break;
case "それ":
textblock.Text = textblock.Text + header + "\r\n";
break;
case "あれ":
textblock.Text = textblock.Text + header + "\r\n";
break;
case "どれ?":
textblock.Text = textblock.Text + header + "\r\n";
break;
default:
textblock.Text = textblock.Text + "???" + "\r\n";
break;
}
}
}
}
senderがクリックされたオブジェクトなのですが、まずこれをMenuItem型に変換(キャスト)します。
変換したオブジェクト(上記のmenuitem)のHeaderプロパティを取り出すとそれもオブジェクト型なので、ToString()メソッドで文字列に変換します。
そうすると、クリックされたMenuItemのHeader文字列を取得できます。
あとは、switch文を使って条件分岐してコードを実行すれば良いわけです。
Tagで識別する編
Headerプロパティで識別するとコードは短く出来ますが、メニューの表示文字列を変更したときにClickイベントのコードの方も変更しなければならなくなります。これは面倒ですね。 ということで、HeaderではなくTagプロパティを使ってみます。
XAMLを下記のようにします。MenuItem要素にTagという属性を追加しました。
<Window x:Class="WpfApp1.MainWindow"
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:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200" >
<Grid>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="やりましょう">
<MenuItem Tag="kore" Header="これ" Click="MenuItem_Click" />
<MenuItem Tag="sore" Header="それ" Click="MenuItem_Click" />
<MenuItem Tag="are" Header="あれ" Click="MenuItem_Click" />
<MenuItem Tag="dore" Header="どれ?" Click="MenuItem_Click" />
</MenuItem>
</Menu>
<TextBlock Name="textblock" />
</DockPanel>
</Grid>
</Window>
そして、コードを下記のようにします。MenuItemのインスタンスから、Tagプロパティを取り出して、ToString()で文字列に変換し、switch文で条件分岐します。
using System.Windows;
using System.Windows.Controls;
namespace WpfApp1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem menuitem = (MenuItem)sender; // オブジェクトをMenuItemクラスのインスタンスにキャストする。
string header = menuitem.Header.ToString(); // Headerプロパティを取り出して、文字列に変換する。
string tag = menuitem.Tag.ToString(); // Tagプロパティを取り出して、文字列に変換する。
switch (tag) // Tag文字列毎の処理
{
case "kore":
textblock.Text = textblock.Text + header + "\r\n";
break;
case "sore":
textblock.Text = textblock.Text + header + "\r\n";
break;
case "are":
textblock.Text = textblock.Text + header + "\r\n";
break;
case "dore":
textblock.Text = textblock.Text + header + "\r\n";
break;
default:
textblock.Text = textblock.Text + "???" + "\r\n";
break;
}
}
}
}
実行結果は、Headerで識別したときと全く同じになります。
この方法なら、ユーザーから見えないTagというプロパティを使って識別するので、メニューの表示文字列(Headerプロパティ)の後からの変更が簡単にできます。
更新日
公開日
広告
C#のコントロールカテゴリの投稿
- C#でコレクションの要素の変更をバインド先のコントロールに反映する方法
- C#のComboBoxを使ってみた
- C#のDataGridで右クリックメニューを作ってみた
- C#のDataGridの罫線と背景色を変えてみた
- C#のListBoxでCheckBoxを並べてみた
- C#のListBoxを使ってみた
- C#のListViewで列のタイトルを変える
- C#のListViewで選択したアイテムを取得する方法
- C#のListViewに文字を入力する方法
- C#のListViewのヘッダーをクリックして列をソートする方法
- C#のListViewを使ってみた
- C#のRadioButtonで選択された項目を調べる(foreach編)
- C#のRadioButtonを試してみた
- C#のTextBoxで最下行に自動でスクロールする方法
- C#のWPFのコントロール一覧
- C#のスライダコントロールを試してみた
- C#のタブをコードから切り替える
- C#のメニューのイベントを1つにまとめてみた