次の方法で共有


Visual Studio 2010 自習書 ~ Do-It-Yourself シリーズ ~
Visual Studio 2010 による Windows アプリケーション開発の基礎

第 9 回 ユーザー コントロール

更新日: 2010 年 12 月 13 日

Zip File ダウンロード (XPS、1.21 MB | PDF、1.22 MB)


目次

  1. ユーザー コントロール
  2. ユーザー コントロールの作成
  3. ユーザー コントロールの利用
    • 依存プロパティを作成する (参考)
  4. まとめ

第 6 回のリソースから第 8 回のテンプレートで、さまざまな方法でコントロールをカスタマイズできることを学びました。今回のテーマであるユーザー コントロールは、既存の 1 つのコントロールをカスタマイズするのではなく、複数のコントロールを組み合わせて 1 つのコントロールのように使うものです。

ここでは、次のことを学習します。

  • ユーザー コントロールの作成
  • ユーザー コントロールの利用

ページのトップへ


1. ユーザー コントロール

第 8 回のテンプレートで解説したとおり、コントロール テンプレートは、その構成要素として複数のコントロールを組み合わせることができます。つまり、複数のコントロールを組み合わせることだけがユーザー コントロールを使う理由ではありません。

コントロール テンプレートを使う場合には「コントロールのプロパティやイベントなどの機能は、対象となるコントロールのものをそのまま使う」のに対し、ユーザー コントロールを作成する場合は、「UserControl クラスから派生したクラスで必要なプロパティや機能を実装する」という違いがあります。コントロール テンプレートは、Button ならボタンとして、CheckBox ならチェック ボックスとしての機能を変えるわけではありません。ユーザー コントロールは、既存のコントロールでは機能が足りない場合、あるいは新しい機能を持つコントロールを実装したい場合に使います。

また、コントロール テンプレートが、ウィンドウ レベルあるいはアプリケーション レベルでの共通化を図るものであるのに対し、ユーザー コントロールは、プロジェクトをまたがって利用できる、コントロール ライブラリとして実装することができます。

なお、独自の機能を持つコントロールを実装するには、既存のコントロール クラスを継承して作成するカスタム コントロールという方法もあります。ユーザー コントロールは、カスタム コントロールに比べて WPF デザイナーを使って容易に開発できる利点があります。

ページのトップへ


2. ユーザー コントロールの作成

まず、新しい WPF アプリケーションを作成します。ただし、ここで作成されたアプリケーションは、後でユーザー コントロールを使うためのものとなります。また、ユーザー コントロールは、プロジェクトの一部として作成することもできますが、ここでは独立したライブラリとして作成します。

ソリューション エクスプローラーで、ソリューション名を右クリックし、[追加] - [新しいプロジェクト] で表示される「新しいプロジェクトの追加」ダイアログで、「WPF ユーザー コントロール ライブラリ」を選びます。名前は「MyControlLibrary」としておきます。

(図をクリックすると拡大図が表示されます)

ソリューション エクスプローラーには、UserControl1.xaml というモジュールを含む MyControlLibrary が追加されます。ここで、UserControl1.xaml を右クリックして [名前の変更] を選び、「NumericBox.xaml」に変更します。

また、コード ビハインド ファイルの UserControl1 というクラス名を右クリックして、[リファクター] - [名前の変更] を選び、「NumericBox」への変更を適用します。

(図をクリックすると拡大図が表示されます)

なお、ライブラリ プロジェクトから UserControl1.xaml を削除して、新しい項目として「WPF ユーザー コントロール」を追加し、名前を NumericBox にすることもできます。

これで、新しいユーザー コントロールを作成する準備ができました。NumericBox.xaml をダブルクリックして、WPF デザイナーを開くと次のようになっています。

これまでは、もっとも外側はウィンドウ (Window) でしたが、ユーザー コントロールの場合には UserControl 型が使われています。このため、タイトルがなく、大きさはデザイナーのための指定 (d:) があるだけです (コントロールの実際の大きさは配置されるときに決まります)。ここでは、少し高さを低くして、横長にしておきます (XAML エディターで d:DesignHeight が 100 になる程度)。

コントロールの中央をクリックすると、配置されている Grid が選択されます。第 2 回のレイアウトで、Grid のレイアウト方法について学びました。ここでは、上辺のやや右寄りの部分をクリックして分割し、さらに左辺の中央部分で分割します。

今回は、プロパティ ウィンドウを使って、分割の設定を変更します。まず、プロパティ ウィンドウの ColumnDefinitions の右側で [...] ボタンをクリックしてコレクション エディターを開きます。ここで、最初の ColumnDefinition は Width を「*」に、2 つめの ColumnDefinition は Width を「20」に設定します。

これで、右側の列は常に 20 ピクセル分、左側の列は残りの幅を占有するようになります。

続いて、プロパティ ウィンドウの RowDefinitions の右側で [...] ボタンをクリックします。ここでは両方の RowDefinition の Height を「*」にします。これで行の高さは常に等分割されます。

次に、TextBox を左側の列で上下にわたるようにし (これで 2 つの領域をまたがることが示されます)、さらに 2 つの Button を右上と右下に配置します (下図)。

[Shift] + クリックを使って、この 3 つのコントロールをまとめて選択し、プロパティ ウィンドウで Height、HorizontalAlignment、Margin、VerticalAlignment、Width の値をリセットします (それぞれのプロパティ名を右クリックして [値のリセット] を選びます)。

さらに、それぞれのコントロールについて、次のようにプロパティの値を設定します。

コントロール プロパティ
textBox1 Text 0
VerticalContentAlignment Center
button1 Content
Button2 Content

この結果、WPF デザイナーは次の図のようになります。

textBox1 の文字列をわかりやすくするためフォント サイズ (FontSize プロパティ) を大きくすることもできます (ただし、コントロールを配置したときに、配置場所のフォント サイズを反映しなくなります)。

続いて、コード ビハインド (NumericBox.xaml.cs) で、このユーザー コントロールの機能を割り当てます。ここには次のように記述してください。

public partial class NumericBox : UserControl
{

  public int Value
  {
    get
    {
      int n;
      if (int.TryParse(textBox1.Text, out n))
        return n;
      return 0;
    }
    set
    {
      textBox1.Text = value.ToString();
    }
  }


  public NumericBox()
  {
    InitializeComponent();
  }
}

ここでは、整数値をあらわす Value プロパティを定義しています。Value の値は、設定するときはテキスト ボックスの文字列として渡され、取得するときはテキスト ボックスに入力されている文字列を整数値に変換して返します。

さらに 2 つのボタンについて、次のように Click イベントのイベント ハンドラーを割り当てます。

private void button1_Click(object sender, RoutedEventArgs e)
{
   Value = Value + 1;
}

   private void button2_Click(object sender, RoutedEventArgs e)
{
   Value = Value - 1;
}

これで、上下のボタンを使える数値入力用のコントロールが完成しました。[Shift] - [F6] などを押して、このプロジェクトをビルドしておいてください。

ページのトップへ


3. ユーザー コントロールの利用

最初に作成した WPF アプリケーション プロジェクトに戻ります。ソリューション エクスプローラーでプロジェクト名を右クリックし、[参照の追加] を選びます。ここで、「プロジェクト」タブを選ぶと、作成した MyControlLibrary ライブラリが表示されています (下図)。

[OK] ボタンを押すと、このプロジェクトからライブラリに登録されているコントロールを使えるようになります。ただし、WPF デザイナーで編集するときには、まだツール ボックスに追加したコントロールは表示されていません。このため、ツール ボックスを右クリックして、[アイテムの選択] を選びます。すると、アイテムの選択画面になるので、[WPF コンポーネント] タブを選び、[参照] ボタンを押します。ここで、先ほどビルドしておいたライブラリ (.dll) を指定します。

(図をクリックすると拡大図が表示されます)

すると、ツール ボックス アイテムの選択で、NumericBox コントロールが表示されてチェックされるので、[OK] ボタンを押します。

ツール ボックスに新しいコントロール (NumericBox) が表示されます。

これで、他のコントロールと同じように、ツール ボックスからドラッグ アンド ドロップして、コントロールを配置できるようになります。テスト用に NumericBox と Button コントロールを 1 つずつ配置し、Button の Click イベントに次のようなイベント ハンドラーを割り当てます。

public partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();
  }


  private void button1_Click(object sender, RoutedEventArgs e)
  {
    MessageBox.Show("Value = " + numericBox1.Value.ToString());
  }

}

プログラムを実行した様子を次に示します。

なお、ここで作成したコントロールは、プログラムで Value プロパティを扱うことはできますが、第 5 回で学んだデータ バインディングの対象として使うことはできません。データ バインディングとして使えるプロパティは、「依存プロパティ」でなければならないためです。
 

依存プロパティを作成する (参考)

依存プロパティの実装は、単純なプロパティの実装よりも複雑になります。前述の NumericBox コントロールの Value プロパティを、依存プロパティとして実装する例を以下に示します。

public partial class NumericBox : UserControl
{

  public int Value
  {
    get { return (int)GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }
  }

  static void valueChangedCallBack(DependencyObject property,
    DependencyPropertyChangedEventArgs args)
  {
    NumericBox searchTextBox = (NumericBox)property;
    searchTextBox.textBox1.Text = args.NewValue.ToString();
  }

  public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value", typeof(int), typeof(NumericBox),
    new FrameworkPropertyMetadata(0,
        new PropertyChangedCallback(valueChangedCallBack)));

  public NumericBox()
  {
    InitializeComponent();
    textBox1.LostFocus += new RoutedEventHandler(textBox1_LostFocus);
  }

  void textBox1_LostFocus(object sender, RoutedEventArgs e)
  {
    int n;
    if (int.TryParse(textBox1.Text, out n))
      Value = n;
    else
      Value = 0;
  }

  ……button1_Clickとbutton2_Click
}

ここで ValueProperty という依存プロパティを静的に定義していることに注意してください。ここに用意されたデータに基づいて、コントロールの外部から間接的にプロパティを変更できる仕組みが提供されています。また、ここでは Value プロパティと TextBox コントロールの Text プロパティが直接連動しないため、TextBox からフォーカスが失われたときに、Value プロパティを更新しています。TextBox にフォーカスがある間 (値を入力している間) は、Value プロパティが変化しない (バインディング対象に影響しない) ことに注意してください。

ページのトップへ


4. まとめ

最初に述べたとおり、既存のコントロールを組み合わせてユーザー コントロールを作成する以外にも、既存のコントロールを拡張してカスタム コントロールを作成する方法があります。これは、既存のコントロールの仕組み (プロパティやイベント) をあまり変更する必要がないものの、コントロール テンプレートのように外観の変更だけで済まない場合に便利です。

全 9 回を通じて学んだとおり、Visual Studio 2010 を活用することで、機能的かつ使いやすい Windows アプリケーションを容易に開発できます。ぜひ、皆さんもチャレンジしてみてください。

ページのトップへ