++C++; // 未確認飛行 C 避けて通れない「非同期処理」を克服しよう

Top総合 目次.NET Framework

XAML とプログラムコード(WPF)

このエントリーをはてなブックマークに追加

目次

キーワード

概要

XAML で記述した GUI に対して、 C# などのプログラミング言語を用いてイベント処理を記述することができます。

ただし、プログラムコードの埋め込みは、 Loose XAML に対してはできず、必ずコンパイルが必要になります。 (参考: 「XAML のコンパイル」 。)

↑ JavaScript を使うならコンパイルが不要な、 Silverlight というものもあります。 Silverlight は Flash の競合となる技術で、 WPF と比べるとかなり機能は制限されていますが、 XAML ベースの GUI アプリケーション開発という点に関しては WPF と同じコンセプトです。

イベント処理

プロパティと同様に、 イベントAttribute SyntaxProperty Element Syntax を用いて設定することができます。

例えば、ボタンが押されたときのイベント処理を追加したければ、 以下のように Click イベントを設定します。

<Window x:Class="XamlWindowsApplication1.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="XAML テストプログラム" Height="100" Width="140"
  >

  <x:Code>
    <![CDATA[
    private void ButtonClicked(object sender, RoutedEventArgs e)
    {
      MessageBox.Show("ボタンが押されました");
      e.Handled = true;
    }
    ]]>
  </x:Code>

  <Button Click="ButtonClicked">ここを押して</Button>

</Window>

この例にあるとおり、 プログラムコードは XAML 中の x:Code タグ中に直接埋め込むことも可能です。 (ただし、これは非推奨。次節で説明するコードビハインドを使いましょう。) x:Code タグも、XML の文法に従う必要があるので、 x:Code タグ中のプログラムコードは CDATA セクションにしてください。 (でないと、< とか > とか & とかの記号が書けない。)

(逆に、XAML を使わなくても、全部 C# などのコードで WPF GUI プログラムを作ることは可能ですが、 ビジュアル/ロジック分離の考え方からするとあまり得策ではありません。)

コードビハインド

イベント処理などのプログラムコードは、先ほどの例のように XAML 中に記述するのではなく、 XAML とは別ファイルにすることが可能です。 このように、XAML で記述した GUI のイベント処理などを別ファイルで与えることを コードビハインド(code-behind)といいます。

例えば、先ほどの例をコードビハインドを使って書き直すと以下のような2つのファイルに分かれます。

<Window x:Class="XamlWindowsApplication1.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="XAML テストプログラム" Height="100" Width="140"
  >

  <Button Click="ButtonClicked">ここを押して</Button>

</Window>
namespace XamlWindowsApplication1
{
  public partial class Window1 : System.Windows.Window
  {
    public Window1()
    {
      InitializeComponent();
    }

    private void ButtonClicked(
      object sender, System.Windows.RoutedEventArgs e)
    {
      System.Windows.MessageBox.Show("ボタンが押されました");
      e.Handled = true;
    }
  }
}

XAML では、ルートの Windows 要素の x:Class 属性で、クラスの名前を記述します。 C# コード側では、同名のクラスを partial クラスを使って定義します。 (partial クラスに関しては、 「クラスの分割定義」 参照。)

GUI 要素の参照

Windows.Forms プログラム( 「GUI アプリケーション」 参照)で this.text1.Text="表示テキスト" などと記述していたように、 XAML 中に記述した GUI 要素(ボタンなど)をコードビハインド中で読み書きできます。 GUI 要素を参照するための名前を指定するには Name 属性を使います。

例えば、先ほどの例で、メッセージボックスの代わりに、テキストブロックにメッセージを表示する場合、 まず、XAML 側では、以下のように、TextBlock 要素に Name 属性をつけます。

<Window x:Class="XamlWindowsApplication1.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="XAML テストプログラム" Height="100" Width="200"
  >

  <StackPanel Orientation="Vertical">
    <Button Click="ButtonClicked">ここを押して</Button>
    <TextBlock Name="textBlock"></TextBlock>
  </StackPanel>

</Window>

これで、このテキストブロックに textBlock という名前が付きました。 C# コード側では、この名前をそのまま変数名として使えます。

namespace XamlWindowsApplication1
{
  public partial class Window1 : System.Windows.Window
  {
    public Window1()
    {
      InitializeComponent();
    }

    int count = 0;

    private void ButtonClicked(
      object sender, System.Windows.RoutedEventArgs e)
    {
      ++this.count;
      this.textBlock.Text =
        string.Format("ボタンが{0}回押されました", this.count);
      e.Handled = true;
    }
  }
}

ちなみに、Button や TextBlock などは、Name プロパティを持っていて、 XAML 中の Name 属性値は、(変数名としてだけでなく)Name プロパティの値にもなります。

一方、Name プロパティを持たない型を XAML 要素として使いたい場合もあるのですが、 その場合、XAML のタグ中には Name 属性は書けません。 このような場合、Name 属性の変わりに x:Name 属性を使います。

ルーティングイベント

Windows.Forms( 「GUI アプリケーション」 参照)では、 ボタンを押されたときとかの処理(イベント処理)は、 C# のイベントを使って実現していました。

対して、 WPF では、少し複雑なイベント処理方式を採用しています。 依存プロパティを用いて、 親要素のプロパティの値を設定したりできたのと同様に、 子要素や親要素で発生したイベントを処理することができます。

例えば、以下のような感じで、 StackPanel の下に連なる Button の Click イベントを、 全部 StackPanel で受けて処理することができます。

<Window x:Class="XamlWindowsApplication1.MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="XAML テストプログラム" Height="100" Width="200"
  >

  <StackPanel Orientation="Vertical" Button.Click="ButtonClicked">
    <Button>ボタン1</Button>
    <Button>ボタン2</Button>
    <Button>ボタン3</Button>
    <Button>ボタン4</Button>
    <Button>ボタン5</Button>
  </StackPanel>

</Window>

このような仕組みは、 XML ツリーを上にたどってイベントが送られていく(route: 送る)ことから、 ルーティングイベント(routed event)と呼ばれています。 (英語だと routed なのに、なぜか和訳はルーティング。)

ちなみに、イベントの発生元(どのボタンが押されたのか)は、 RoutedEventArgs ee.Source を見れば分かります。 例えば、以下のようにすると、 どのボタンが押されたのかをメッセージボックスで表示するようなプログラムになります。

using System.Windows;
using System.Windows.Controls;

namespace XamlWindowsApplication1
{
  public partial class MainWindow : System.Windows.Window
  {
    public MainWindow()
    {
      InitializeComponent();
    }

    private void ButtonClicked(object sender, RoutedEventArgs e)
    {
      Button b = (Button)e.Source;
      MessageBox.Show("「" + b.Content.ToString() + "」が押されました");
      e.Handled = true;
    }
  }
}

スタイル中でのイベントハンドラの設定

(書きかけ)

スタイル中で、 Setter を使ってプロパティの値を設定できたのと同様に、 EventSetter を使ってイベントハンドラを設定できます。

リソース

(書きかけ)

(TypeName)this.FindResource("Rosource Key");

[お問い合わせ](q)