6.2 ボタン
6.2.1 通常のボタン
ボタンは、ラベルと同様にテキストやアイコンを表示することができるコントロールですが、それに加えて「押す」という動作が加えられています。ボタンのように「押す」という機能を提供するコントロールは、System.Windows.Controls.Primitives.ButtonBase クラスに抽象化されています。
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Media.Visual System.Windows.UIElement System.Windows.FrameworkElement System.Windows.Controls.Control System.Windows.Controls.ContentControl System.Windows.Controls.Primitives.ButtonBase
[LocalizabilityAttribute(LocalizationCategory.Button)] public abstract class ButtonBase : ContentControl, ICommandSource
ButtonBase クラスは、ボタン的な機能を提供するコントロールのルートとなる抽象クラスです。通常のボタンはもちろん、チェックボックスやラジオボタンなども含めて、全てのボタン機能を提供するクラスは、このクラスから派生しています。
通常のボタンを表示するには System.Windows.Controls.Button クラスを利用します。このクラスのボタンは、単純に押す機能だけを提供します。ユーザーは、ボタンを押すことで、ボタンに関連付けられている何らかの機能が実行されることを期待するでしょう。
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Media.Visual System.Windows.UIElement System.Windows.FrameworkElement System.Windows.Controls.Control System.Windows.Controls.ContentControl System.Windows.Controls.Primitives.ButtonBase System.Windows.Controls.Button
public class Button : ButtonBase
このクラスのコンストラクタは、パラメータを受けません。
public Button ()
ボタン上に表示されるテキストなどは、ラベルなどと同様に Content プロパティに設定されているコンテンツです。そのため、任意の UIElement をボタンに設定できるので、必要であればテキスト意外に、イメージや任意の図形をボタン上に表示させることができます。
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main() { Button button1 = new Button(); button1.Content = "Melancholy"; Button button2 = new Button(); button2.Content = "Sighs"; StackPanel panel = new StackPanel(); panel.Children.Add(button1); panel.Children.Add(button2); Window wnd = new Window(); wnd.Content = panel; Application app = new Application(); app.Run(wnd); } }
コード1は、単純にテキストだけを表示するボタンを 2 つ表示しています。マウスの左クリックなどでボタンを押すと、ボタンの外見も奥に押し込まれたようなイメージに変更されます。ボタンを離すと、ボタンのイメージは元に戻ります。この動作は、Windows 標準的なボタンと同じであることが分かります。
6.2.2 クリックイベント
ボタンが押されると ButtonBase クラスの Click イベントが発生します。ButtonBase は、ボタン関連のコントロールに共通する抽象コントロールなので、ラジオボタンなど、その他の種類のボタンの場合でも Click イベントを用いて処理することができます。ButtonBase クラスは、ボタンに共通する多くの機能を提供しています。
public event RoutedEventHandler Click
Click イベントには、System.Windows.RoutedEventHandler デリゲート型のオブジェクトを追加することができます。
public delegate void RoutedEventHandler ( Object sender, RoutedEventArgs e )
RoutedEventHandler は、前述したルーティングによって呼び出されるイベントハンドラが共通して受ける RoutedEventArgs オブジェクトをパラメータで受け取ります。マウスやキーボードイベントで受けた MouseButtonEventArgs クラスも RoutedEventArgs クラスから派生しています。Click は、クリックされたと言う事実の通知のみが重要であり、それ以外にクリック専用の情報を付属させる必要がないため RoutedEventArgs 以外の情報はありません。ボタンが押されたことを処理するために、カーソルの座標は不要でしょう。
using System; using System.Windows; using System.Windows.Media; using System.Windows.Controls; class Test : Window { [STAThread] public static void Main() { Window wnd = new Test(); Application app = new Application(); app.Run(wnd); } private Button button; public Test() { button = new Button(); button.Content = "押してください"; button.Click += buttonClick; Content = button; } private void buttonClick(Object sender, RoutedEventArgs e) { button.Background = Brushes.Red; } }
コード2は、ウィンドウ上のボタンを押すと、ボタンの背景色を赤色に変更するプログラムです。表示する Button オブジェクトの Click イベントに、buttonClick() メソッドのへのデリゲートを登録することで、ボタンが押されたときに呼び出されます。そして、buttonClick() メソッドでボタンの背景色を変更しています。
6.2.3 チェックボックス
チェックボックスやラジオボタンのように、チェック状態の切り替えが可能なボタンは System.Windows.Controls.Primitives.ToggleButton クラスで抽象化されています。このクラスもまた、Button クラスと同様に ButtonBase クラスから派生しています。
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Media.Visual System.Windows.UIElement System.Windows.FrameworkElement System.Windows.Controls.Control System.Windows.Controls.ContentControl System.Windows.Controls.Primitives.ButtonBase System.Windows.Controls.Primitives.ToggleButton
public class ToggleButton : ButtonBase
チェックボックスやラジオボタンは、このクラスから派生しています。これらの種類のボタンに共通する機能は ToggleButton クラスで宣言されています。チェックボックスを利用するには ToggleButton クラスを継承する System.Windows.Controls.CheckBox クラスを利用します。
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Media.Visual System.Windows.UIElement System.Windows.FrameworkElement System.Windows.Controls.Control System.Windows.Controls.ContentControl System.Windows.Controls.Primitives.ButtonBase System.Windows.Controls.Primitives.ToggleButton System.Windows.Controls.CheckBox
[LocalizabilityAttribute(LocalizationCategory.CheckBox)] public class CheckBox : ToggleButton
CheckBox クラスのコンストラクタは、パラメータを受け取りません。
public CheckBox ()
チェックボックスにテキストなどを表示する方法はボタンと同じです。Content プロパティから任意のオブジェクトを設定することで、テキストやアイコンを表示することができます。
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main() { CheckBox checkBox1 = new CheckBox(); checkBox1.Content = "Boredom"; CheckBox checkBox2 = new CheckBox(); checkBox2.Content = "Vanish"; StackPanel panel = new StackPanel(); panel.Children.Add(checkBox1); panel.Children.Add(checkBox2); Window wnd = new Window(); wnd.Content = panel; Application app = new Application(); app.Run(wnd); } }
コード3は、2 つのチェックボックスを表示するだけの単純なプログラムです。これらのチェックボックスには、クリックすることでチェックを入れることができます。ただし、このプログラムではイベントを何も処理していないので、チェックを入れることで何か動作が発生するわけではありません。
ボタンのチェック状態をプログラム側で調べたり、プログラム側でチェック状態を変更するには IsChecked プロパティを利用します。
[LocalizabilityAttribute(LocalizationCategory.None, Readability=Readability.Unreadable)] [TypeConverterAttribute(typeof(NullableBoolConverter))] public Nullable<bool> IsChecked { get; set; }
IsChecked プロパティは ToggleButton クラスで宣言されているプロパティなので、チェック可能なボタンのクラスで共通に利用することができます。IsChecked は bool 型でチェック状態を返しますが、このプロパティ型は Nullable 型なので未定義の場合は null を返します。
既定では、このプロパティには false が設定されていますが、例えば、入力が必須のチェックボックスの場合、IsChecked プロパティに null を代入してみて意義であることをアピールすることができます。true や false だけの値では、ユーザーが明示的に合意した結果であるかどうか、プログラムは判断することができません。しかし、チェックボックスを表示する前に未定義に初期化しておけば、ユーザーが明示的にチェックしたかどうかを調べることができます。
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main() { CheckBox checkBox1 = new CheckBox(); checkBox1.IsChecked = true; checkBox1.Content = "チェック状態"; CheckBox checkBox2 = new CheckBox(); checkBox2.IsChecked = false; checkBox2.Content = "非チェック状態"; CheckBox checkBox3 = new CheckBox(); checkBox3.IsChecked = null; checkBox3.Content = "未定義"; StackPanel panel = new StackPanel(); panel.Children.Add(checkBox1); panel.Children.Add(checkBox2); panel.Children.Add(checkBox3); Window wnd = new Window(); wnd.Content = panel; Application app = new Application(); app.Run(wnd); }
コード4は、実行時のクリックではなく、ウィンドウを表示する前にアプリケーション側でチェックボックスの状態を制御しています。ウィンドウが表示されると、既定でチェック状態、非チェック状態、未定義の状態のコントロールがそれぞれ表示されます。
チェックボックスは、それ自体がチェック状態であるかどうかを表す IsChecked プロパティを持つため、チェック状態を入力することが目的であればチェックボックスそのものがイベントを処理する必要は無いでしょう。実践的なフォームの場合、チェックボックス自体が何らかの動作を提供することは少なく、単純にユーザーにチェックするかどうかの選択を与える目的に利用することが多いでしょう。しかし、チェックボックスがチェックされたり、またはチェックが外されたりする瞬間に何らかの処理を介入させたい場合、イベントを監視する必要があります。
チェックボックスのチェック状態の変更はクリックによって発生するため、一般的な監視方法としては Click イベントを処理する形でも良いかもしれませんが、別のコードから直接 IsChecked プロパティが変更された場合など、チェック状態の変更を厳密に監視したい場合は Click イベントの処理だけでは不十分です。このような場合、チェック状態になったときに発生する Checked イベントと、非チェック状態になったときに発生する Unchecked イベントを利用します。
public event RoutedEventHandler Checked
public event RoutedEventHandler Unchecked
これらのイベントに適切なデリゲートを追加すれば、IsChecked プロパティが変更されたタイミングで対応するイベントハンドラが呼び出されます。
using System; using System.Windows; using System.Windows.Controls; class Test : Window { [STAThread] public static void Main() { Window wnd = new Test(); Application app = new Application(); app.Run(wnd); } private Label label; private CheckBox checkBox; public Test() { label = new Label(); label.Content = "チェック状態を表示します"; checkBox = new CheckBox(); checkBox.Content = "押してください"; checkBox.Checked += checkBoxChecked; checkBox.Unchecked += checkBoxUnchecked; StackPanel panel = new StackPanel(); panel.Children.Add(label); panel.Children.Add(checkBox); Content = panel; } private void checkBoxChecked(Object sender, RoutedEventArgs e) { label.Content = "チェックされました"; } private void checkBoxUnchecked(Object sender, RoutedEventArgs e) { label.Content = "解除されました"; } }
コード5は、チェックボックスのチェック状態を変更すると、上部のラベルのテキストが変更するというプログラムです。チェックボックスをクリックするとチェック状態が変更され、その結果 Checked や Unchecked イベントが発生します。これらのイベントで呼び出されるメソッドで、ラベルのテキストを変更しています。
6.2.4 ラジオボタン
一般に、排他的なチェック項目にはラジオボタンが使われます。ラジオボタンは System.Windows.Controls.RadioButton クラスを使います。このクラスは、CheckBox クラスと同様に ToggleButton クラスを継承しています。
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Media.Visual System.Windows.UIElement System.Windows.FrameworkElement System.Windows.Controls.Control System.Windows.Controls.ContentControl System.Windows.Controls.Primitives.ButtonBase System.Windows.Controls.Primitives.ToggleButton System.Windows.Controls.RadioButton
[LocalizabilityAttribute(LocalizationCategory.RadioButton)] public class RadioButton : ToggleButton
このクラスのコンストラクタは、パラメータを受け取りません。
public RadioButton ()
同一のパネル内にあるラジオボタンのチェックは互いに排他的です。そのため、あるラジオボタンにチェックを入れると、他のラジオボタンのチェックは自動的に解除されます。
using System; using System.Windows; using System.Windows.Controls; class Test : Window { [STAThread] public static void Main() { Window wnd = new Test(); Application app = new Application(); app.Run(wnd); } private Label label; private RadioButton button1, button2; public Test() { label = new Label(); label.Content = "私の名前、覚えている?"; button1 = new RadioButton(); button1.Content = "ハナコ"; button1.Checked += button1Checked; button2 = new RadioButton(); button2.Content = "ジロウ"; button2.Checked += button2Checked; StackPanel panel = new StackPanel(); panel.Children.Add(label); panel.Children.Add(button1); panel.Children.Add(button2); Content = panel; } private void button1Checked(Object sender, RoutedEventArgs e) { label.Content = "違うよぉ~"; } private void button2Checked(Object sender, RoutedEventArgs e) { label.Content = "私、女の子…"; } }
コード6は、同一の StackPanel 上に 2 つのラジオボタンを配置しています。これらのラジオボタンの一方にチェックを入れると、もう一方のチェックは自動的に解除されます。