連載
» 2011年01月06日 00時00分 公開

連載:WPF入門:第8回 WPFの「コントロール」を学ぼう (1/2)

GUIアプリケーション開発の主役である「コントロール」を中心に、WPFのUI要素について説明。コントロールの全体像と基礎を説明し、用途ごとに分類する。

[岩永信之(http://ufcpp.net/),著]
連載:WPF入門
業務アプリInsider/Insider.NET

powered by Insider.NET

「連載:WPF入門」のインデックス

連載目次

 レイアウト用のパネルに続き、今回は、「ユーザー/アプリケーション間の対話を担う要素」、いわゆるコントロールを中心として、WPFのUI要素について説明していく。

■コントロール

 コントロールは、ユーザーとの対話を担う要素で、GUIアプリケーション開発の中心的存在といえる。コントロールは、マウスやキーボードなどのユーザー操作を受け取ったり、処理の途中経過や結果を適宜表示したりするために利用する。

コントロールの全体像

 まず、コントロールや、関連するUI要素のクラス階層を見てみよう。主要なものをFigure 1に示す。

Figure 1: WPFの主要なUI要素

 前回説明したとおり、FrameworkElementクラス(System.Windows名前空間)はWPFのほとんどのUI要素の共通基底となる基礎的なクラスで、Panelクラス(System.Windows.Controls名前空間)は子要素と協調してレイアウトを決定するためのパネルの基底クラスである。

 一方、今回初出となるDecoratorクラス(System.Windows.Controls名前空間)は、子要素やその周辺に何らかの装飾を施すためのクラスで、例えば、UI要素の回りを枠線で囲ったり、ビュレット(=個条書き用の中点)を付けたりするために用いる。

 そして、Controlクラス(System.Windows.Controls名前空間)が、今回の主題であるコントロールの基底クラスとなる。

 それではまず、Controlクラスをはじめ、さまざまなコントロールの基底クラスとなるいくつかの主要なクラス(=Figure 1で、青色の枠線で囲われているもの)について説明していこう。

■主要な基底クラス

Controlクラス

 Controlクラスはすべてのコントロールの基底となるクラスで、Table 1に示すようなメンバを持っている。

機能 メンバ
外観設定 Background
BorderBrush
BorderThickness
Foreground
フォント FontFamily
FontSize
FontStretch
FontStyle
FontWeight
内容物のレイアウト決定 HorizontalContentAlignment
VerticalContentAlignment
Padding
フォーカス管理 IsTabStop
TabIndex
コントロール・テンプレート Template
マウス・イベント MouseDoubleClick
PreviewMouseDoubleClick
Table 1: Controlクラスの機能
マウス・イベントの各メンバはルーティング・イベントである。それ以外はすべてプロパティ。

 以下、何点か補足説明をしていこう。

外観設定

 Backgroundプロパティ、Foregroundプロパティ、および、BorderBrushプロパティは、それぞれ背景や前景、枠線の塗りつぶしを行うためのブラシとなっている。純色での塗りつぶしだけでなく、以下のようなブラシを利用することで、グラデーションや画像を使った塗りつぶしも可能である。

  • SolidColorBrush: 純色で塗りつぶす。
  • LinearGradientBrush: 線形グラデーションで塗りつぶす。
  • RadialGradientBrush: 放射状グラデーションで塗りつぶす。
  • ImageBrush: 画像を使って塗りつぶす。
  • DrawingBrush: Drawingクラス(=2D描画)を使って塗りつぶす。
  • VisualBrush: Visualクラス(=WPFのUI要素の共通基底クラス)を使って塗りつぶす。

 例えば、DrawingBrushに対して<VideoDrawing>要素を与えたり、VisualBrushに対して<MediaElement>要素を与えたりすることで、コントロールの背景に動画を表示することも可能である。

 SolidColorBrushの場合には、RGB値や色名からの変換が定義されていて、XAMLの属性構文を使って以下のような色指定が可能である。

<!-- # 6ケタの16進数で RGB 指定。 -->
<TextBox Background="#0000ff" />

<!-- 色名からの変換が働く。
     Colors クラスの静的メンバーとして定義されている。 -->
<TextBox Background="Blue" />

<!-- SystemColors クラスの静的メンバーを参照することで、
     システム色を利用可能。 -->
<TextBox Background="{x:Static SystemColors.ActiveCaptionBrush}" />

XAMLの属性構文を使ったSolidColorBrushの色指定のコード例(XAML)

 どのような色名やシステム色が利用できるかは、MSDNの「Colorsクラス(System.Windows.Media名前空間)」および「SystemColorsクラス(System.Windows名前空間)」のページを参照してほしい。

 また、LinearGradientBrush、RadialGradientBrush、および、ImageBrushは、Visual StudioやExpression Blendを使ってブラシの設定が可能である。Movie 1に、Visual Studioを使ったブラシ設定の例を示す。


フォント

 フォントに関しては、ファミリ、サイズ、スタイル(=標準/太字/斜体/打ち消し線付き/下線付き)、線の太さ、伸縮と、一通り設定可能になっている。このうち、フォント・ファミリについて補足しておこう。

 FontFamilyプロパティに単にフォント名を指定した場合、システムにインストールされたフォントが利用される。当然、指定されたフォントがインストールされていない環境では、そのフォントが適用されない(既定のフォントが使用される)。

<!-- システムにインストールされたフォントを使う。 -->
<!-- フォントがインストールされていない環境では適用されない。 -->
<TextBlock Text="テスト 試作" FontFamily="HGPGyoshotai" />

フォント・ファミリ指定のコード例(XAML)

 システムにフォントがインストールされていない場合を想定して、フォント・ファミリはカンマ区切りで複数指定可能である。

 また、どんな環境でも意図したとおりのフォントで表示できるように、アプリケーションにフォントを埋め込むこともできる。

 手順としては、まず、フォントをアセンブリ・リソース(=Visual Studioの[プロパティ]ウィンドウで[ビルド アクション]を「Resource」にしたもの)としてアプリケーションに埋め込む。そして、XAMLコード中では、「FontFamily="./#font name"」というように、「#」に続けてフォント名を記述する。

 Figure 2に、フォントの埋め込みの例を示す。

Figure 2: フォントの埋め込みの例
ちなみに、このサンプルで指定している「たぬき油性マジック」は商用利用可能なフリー・フォント。

 ただし、配布を自由に認めているフォントでも、アプリケーションへ埋め込んでの配布は認めていない場合があるので、ライセンスに注意が必要である。

ContentControlクラス

 ContentControlクラス(System.Windows.Controls名前空間)は、ボタンなどのように、コンテンツを1つだけ持つコントロールの基底クラスである。アプリケーション本体となることの多いWindowクラスもContentControlクラスから派生している。

 コンテンツを表すContentプロパティはobject型になっていて、何でも格納することができる。格納した型によって、以下のように、異なる表示が行われる。

  • UIElementクラスの場合、そのままUI要素として表示が行われる(OnRenderメソッドで描画を行う)
  • そのほかのクラスの場合、データ・テンプレートが設定されていればテンプレートを使った表示が行われる(連載第5回を参照)
  • データ・テンプレートも設定されていない場合、ToStringメソッドを使って文字列化された結果が表示される

 ContentControlクラスの派生クラスの中に複数のUI要素を並べたい場合、まず<Grid>要素などのパネルを置いて、その中にUI要素を並べる。

 コンテンツへのテンプレート適用は、ContentTemplateプロパティで明示的に指定するか、第5回で説明したようにDataTypeプロパティを使った自動適用で行う。

HeaderedContentControlクラス

 Figure 3に示すように、<GroupBox>要素や<Expander>要素など、一部のコントロールはヘッダ情報とコンテンツを持っている。このようなコントロールの基底となるのがHeaderedContentControlクラス(System.Windows.Controls名前空間)である。

Figure 3: ヘッダとコンテンツを持つコントロールの例

 ヘッダ情報を指定するためのHeaderプロパティもContentプロパティと同様にobject型となっていて、データ・テンプレートやToStringメソッドを介した表示が行われる。データ・テンプレートを明示的に指定したい場合にはHeaderTemplateプロパティを使って指定する。

ItemsControlクラス

 ItemsControlクラス(System.Windows.Controls名前空間)は、<ListBox>要素などのように複数の項目を持つコントロールの基底クラスである。ItemsControlクラスの内部構造はFigure 4に示すようになっていて、以下のように、カスタマイズできる個所が3つある。

  • item: <ItemsControl>要素内に表示したい項目。ItemsSourceプロパティを通して与える。<ContentControl>要素のContentプロパティと同様に、データ・テンプレートが適用可能で、明示的にテンプレートを与えたい場合にはItemTemplateプロパティを用いる。
  • container: ItemsSourceプロパティで与えた項目は直接表示されるわけではなく、1段階コンテナを挟んで表示される。コンテナは、ListBoxコントロールなら<ListBoxItem>要素、ComboBoxコントロールなら<ComboBoxItem>要素というように、ItemsControlクラスの派生クラスごとに決まっている。コンテナを丸ごと差し替えることはできないが、ItemContainerStyleプロパティを用いることでスタイルの変更が可能である。
  • item panel: 複数の項目のレイアウトを決定するためのパネル。ItemsPanelプロパティで明示的に指定することで、レイアウト方法を変えられる。
Figure 4: ItemsControlクラスの内部構造

 List 1にItemsControlクラスのカスタマイズの例を、Figure 5にその表示結果を示す。

<Window x:Class="atmarkit08.ItemsControlSample"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="ItemsControlサンプル" Height="150" Width="150">
  <Grid>

    <ItemsControl ItemsSource="{Binding}">

      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <CanvasItemsPanelTemplate>
      </ItemsControl.ItemsPanel>

      <ItemsControl.ItemContainerStyle>
        <Style>
          <Setter Property="Canvas.Left" Value="{Binding X}" />
          <Setter Property="Canvas.Top" Value="{Binding Y}" />
        </Style>
      </ItemsControl.ItemContainerStyle>

      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <Button Content="{Binding Text}" />
        </DataTemplate>
      </ItemsControl.ItemTemplate>

    </ItemsControl>

  </Grid>
</Window>

this.DataContext = new[]
{
  new { Text = "a", X = 20, Y = 80 },
  new { Text = "b", X = 80, Y = 80 },
  new { Text = "c", X = 80, Y = 20 },
  new { Text = "d", X = 20, Y = 20 },
};

Me.DataContext =
{
  New With { .Text = "a", .X = 20, .Y = 80 },
  New With { .Text = "b", .X = 80, .Y = 80 },
  New With { .Text = "c", .X = 80, .Y = 20 },
  New With { .Text = "d", .X = 20, .Y = 20 }
}

List 1: ItemsControlクラスのカスタマイズの例(上:XAML、中:C#、下:VB)

Figure 5: List 1の表示結果

 この例では、ItemsPanelプロパティに<Canvas>要素を指定することで、頒布図のようなレイアウトを行っている。Canvas.Left添付プロパティは<Canvas>要素の直接の子要素に指定する必要があるため、ItemTemplateプロパティに指定するデータ・テンプレート内ではなく、ItemContainerStyleプロパティに指定するスタイル内で設定しなければならない。

コレクション・ビュー

 ItemsSourceプロパティ経由で<ItemsControls>要素に渡されたデータ・ソースは、Figure 6に示すように、実際には間にコレクション・ビュー(collection view)というものが挟まったうえで表示される。コレクション・ビューは、データ・ソースを変更せずに、ビュー上でだけデータの整列やグループ化を行うためのものである。

Figure 6: コレクション・ビュー

 コレクション・ビューという言葉は、名称に「ビュー」という言葉が入っているのが少し紛らわしいが、いわゆる「ビューとモデル」のビュー(見た目に関する部分)のことではなく、データベース用語のビュー(=表示用にデータ・ソースを整形したもの)の意味合いで使われている。

 ItemsControlクラスのItemsSourceプロパティに、コレクション・ビューを表すICollectionViewインターフェイス(System.ComponentModel名前空間)のインスタンスを渡すと、それがそのまま表示されるが、ほかのコレクションを与えた場合には、内部的にコレクション・ビューが作成され、ラッピングされる。

 ItemsControlクラスには、ItemsSourceプロパティのほかに、Itemsプロパティというものもあるが、こちらはこのコレクション・ビューに対して直接要素の追加や読み出しを行う場合に利用する。

 XAMLコード中で明示的にコレクション・ビューを作りたい場合、<CollectionViewSource>要素(System.Windows.Data名前空間)を利用する。List 2にコレクション・ビューの利用例を、Movie 2にその実行結果を示す。

<Window x:Class="atmarkit08.CollectionViewSourceSample"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:cm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
 xmlns:dat="clr-namespace:System.Windows.Data;assembly=PresentationFramework"
    Title="CollectionViewサンプル" Height="500" Width="500">

  <Window.Resources>

    <CollectionViewSource x:Key="Sorted" Source="{Binding}">
      <CollectionViewSource.SortDescriptions>
        <cm:SortDescription PropertyName="Category" />
      </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>

    <CollectionViewSource x:Key="Grouped" Source="{Binding}">
      <CollectionViewSource.GroupDescriptions>
        <dat:PropertyGroupDescription PropertyName="Category" />
      </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>

  </Window.Resources>

  <Grid>

    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="auto" />
      <RowDefinition Height="*" />
      <RowDefinition Height="auto" />
      <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <TextBlock Text="同じコレクション・ビューを参照"
      Grid.ColumnSpan="2" HorizontalAlignment="Center" />
    <DataGrid
      ItemsSource="{Binding}" Grid.Row="1" Grid.Column="0" />
    <DataGrid
      ItemsSource="{Binding}" Grid.Row="1" Grid.Column="1" />
 
    <TextBlock Text="SortDescription 付き" Grid.Row="2" />
    <DataGrid
      ItemsSource="{Binding Source={StaticResource Sorted}}"
      Grid.Row="3" Grid.Column="0" />

    <TextBlock Text="GroupDescription 付き"
      Grid.Row="2" Grid.Column="1" />
    <DataGrid
      ItemsSource="{Binding Source={StaticResource Grouped}}"
      Grid.Row="3" Grid.Column="1">
      <DataGrid.GroupStyle>
        <GroupStyle />
      </DataGrid.GroupStyle>
    </DataGrid>

  </Grid>

</Window>

this.DataContext = new[]
{
  new { Name="Button", Category="ボタン" },
  new { Name="CheckBox", Category="選択" },
  new { Name="ComboBox", Category="選択" },
  new { Name="TextBlock", Category="文字表示" },
  new { Name="RadioButton", Category="選択" },
  new { Name="RichTextBlock", Category="文字表示" },
  new { Name="ScrollBar", Category="表示" },
  new { Name="ToolTip", Category="表示" },
};

Me.DataContext =
{
  New With { .Name="Button", .Category="ボタン" },
  New With { .Name="CheckBox", .Category="選択" },
  New With { .Name="ComboBox", .Category="選択" },
  New With { .Name="TextBlock", .Category="文字表示" },
  New With { .Name="RadioButton", .Category="選択" },
  New With { .Name="RichTextBlock", .Category="文字表示" },
  New With { .Name="ScrollBar", .Category="表示" },
  New With { .Name="ToolTip", .Category="表示" }
}

List 2: コレクション・ビューの利用例(上:XAML、中:C#、下:VB)


 この例では、2行2列で4つの<DataGrid>要素を表示している。上の2つは同じデータ・ソースを参照していて(内部的に生成されるコレクション・ビューも同じものが共有される)、片方での整列の結果が他方にも反映される。下の2つの<DataGrid>要素には、それぞれ整列およびグループ化されたコレクション・ビューを与えている。

HeaderedItemsControlクラス

 Figure 7に示すように、<MenuItem>要素や<TreeViewItem>要素など、ヘッダ情報と複数の項目を持っているものもあり、このようなコントロールはHeaderedItemsControlクラス(System.Windows.Controls名前空間)を基底クラスとしている。

Figure 7: ヘッダと複数の項目を持つコントロールの例

 次のページでは、WPFのコントロールを用途ごとに分類する。

       1|2 次のページへ

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。