特集
» 2010年12月14日 00時00分 公開

特集:Visual Studio 2010で社内C/Sシステム開発(前編):Visual Studio 2010でユーザー・インターフェイス開発 (3/3)

[一色政彦,デジタルアドバンテージ]
前のページへ 1|2|3       

■メニュー選択によるコンテンツ領域の切り替え

 ここでは、メニューが選択されたときにコンテンツ領域を切り替える処理を実装する。

コンテンツ領域となるユーザー・コントロールの作成

 コンテンツ領域に表示するユーザー・コントロールを5つ作成しておこう。

 [ソリューション エクスプローラー]にあるプロジェクト項目の右クリック・メニューから[追加]−[ユーザー コントロール]を実行する。[新しい項目の追加]ダイアログが表示されるので、下記の名前でファイルを作成する。

  1. ContetObentoOrder
  2. ContetObentoEntry
  3. ContetObentoList
  4. ContetUserEntry
  5. ContetUserList

 WPFデザイナで、それぞれのユーザー・コントロールの.xamlファイルが表示されたら、TextBlockコントロールをドラッグ&ドロップで配置して、そのTextプロパティにファイルと同じ名前を設定しておこう。なおこれは、ユーザー・コントロールの切り替え状況が認識しやすいようにするための一時的な実装である。

メニューのChecked/Uncheckedイベント・ハンドラ

 メニューが選択された状態か/されていない状態かは、ToggleButtonコントロールのIsCheckedプロパティの値がTrueか/Falseかで判別できる。このIsCheckedプロパティが変更されたときに発行されるのが、Checked/Uncheckedイベント・ハンドラである。従ってここでは、5つのメニュー・ボタンのChecked/Uncheckedイベント・ハンドラを追加する。

 これらのイベント・ハンドラも一括で設定しよう。一括してイベント・ハンドラを設定するには、[ドキュメント アウトライン]ウィンドウで[Ctrl]キーを押したまま、各ToggleButtonコントロールを次々とクリックして選択したうえで、[プロパティ]ウィンドウで[イベント]タブを開き、[Checked]イベントの入力欄に「Menu_Checked」を、[Unchecked]イベントの入力欄に「Menu_Unchecked」を指定すればよい。

 Menu_Checked/Menu_Uncheckedメソッドが追加されるので、下記のコードに書き直してほしい。

using System.Windows;
using System.Windows.Controls.Primitives;
using Microsoft.Windows.Controls.Ribbon;

public MainWindow()
{
  InitializeComponent();

  ContentControlMain.Content = new ContetObentoOrder();
}

private void Menu_Checked(object sender, RoutedEventArgs e)
{
  if (ContentControlMain != null)
  {
    SwitchContent(((ToggleButton)sender).Name);
  }
}

private void SwitchContent(string senderName)
{
  // 該当メニュー以外のチェックをオフにする。
  // なお、クリックされたメニューは自動的にチェックが入る。
  if (senderName != "MenuObentoOrder")
    MenuObentoOrder.IsChecked = false;
  if (senderName != "MenuObentoEntry")
    MenuObentoEntry.IsChecked = false;
  if (senderName != "MenuObentoList")
    MenuObentoList.IsChecked = false;
  if (senderName != "MenuUserEntry")
    MenuUserEntry.IsChecked = false;
  if (senderName != "MenuUserList")
    MenuUserList.IsChecked = false;

  switch (senderName)
  {
    case "MenuObentoOrder":
      ContentControlMain.Content = new ContetObentoOrder();
      ChangeRibbonTabVisibility(senderName);
      break;
    case "MenuObentoEntry":
      ContentControlMain.Content = new ContetObentoEntry();
      ChangeRibbonTabVisibility(senderName);
      break;
    case "MenuObentoList":
      ContentControlMain.Content = new ContetObentoList();
      ChangeRibbonTabVisibility(senderName);
      break;
    case "MenuUserEntry":
      ContentControlMain.Content = new ContetUserEntry();
      ChangeRibbonTabVisibility(senderName);
      break;
    case "MenuUserList":
      ContentControlMain.Content = new ContetUserList();
      ChangeRibbonTabVisibility(senderName);
      break;
  }
}

private void ChangeRibbonTabVisibility(string senderName)
{
  if (senderName == "MenuObentoOrder")
    TabObentoOrder.Visibility = Visibility.Visible;
  if (senderName == "MenuObentoEntry")
    TabObentoEntry.Visibility = Visibility.Visible;
  if (senderName == "MenuObentoList")
    TabObentoList.Visibility = Visibility.Visible;
  if (senderName == "MenuUserEntry")
    TabUserEntry.Visibility = Visibility.Visible;
  if (senderName == "MenuUserList")
    TabUserList.Visibility = Visibility.Visible;

  if (senderName != "MenuObentoOrder")
    TabObentoOrder.Visibility = Visibility.Hidden;
  if (senderName != "MenuObentoEntry")
    TabObentoEntry.Visibility = Visibility.Hidden;
  if (senderName != "MenuObentoList")
    TabObentoList.Visibility = Visibility.Hidden;
  if (senderName != "MenuUserEntry")
    TabUserEntry.Visibility = Visibility.Hidden;
  if (senderName != "MenuUserList")
    TabUserList.Visibility = Visibility.Hidden;
}


private void Menu_Unchecked(object sender, RoutedEventArgs e)
{
  if (ContentControlMain != null)
  {
    if ((MenuObentoOrder.IsChecked == false) &&
      (MenuObentoEntry.IsChecked == false) &&
      (MenuObentoList.IsChecked == false) &&
      (MenuUserEntry.IsChecked == false) &&
      (MenuUserList.IsChecked == false))
    {
      ((ToggleButton)sender).IsChecked = true;
    }
  }
}

Imports System.Windows.Controls.Primitives

Public Sub New()
  InitializeComponent()

  ContentControlMain.Content = New ContetObentoOrder()
End Sub

Private Sub Menu_Checked(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles MenuUserList.Checked, MenuUserEntry.Checked, MenuObentoList.Checked, MenuObentoEntry.Checked, MenuObentoOrder.Checked
  If ContentControlMain IsNot Nothing Then
    SwitchContent(DirectCast(sender, ToggleButton).Name)
  End If
End Sub

Private Sub SwitchContent(ByVal senderName As String)
  ' 該当メニュー以外のチェックをオフにする。
  ' なお、クリックされたメニューは自動的にチェックが入る。
  If senderName <> "MenuObentoOrder" Then
    MenuObentoOrder.IsChecked = False
  End If
  If senderName <> "MenuObentoEntry" Then
    MenuObentoEntry.IsChecked = False
  End If
  If senderName <> "MenuObentoList" Then
    MenuObentoList.IsChecked = False
  End If
  If senderName <> "MenuUserEntry" Then
    MenuUserEntry.IsChecked = False
  End If
  If senderName <> "MenuUserList" Then
    MenuUserList.IsChecked = False
  End If

  Select Case senderName
    Case "MenuObentoOrder"
      ContentControlMain.Content = New ContetObentoOrder()
      ChangeRibbonTabVisibility(senderName)
      Exit Select
    Case "MenuObentoEntry"
      ContentControlMain.Content = New ContetObentoEntry()
      ChangeRibbonTabVisibility(senderName)
      Exit Select
    Case "MenuObentoList"
      ContentControlMain.Content = New ContetObentoList()
      ChangeRibbonTabVisibility(senderName)
      Exit Select
    Case "MenuUserEntry"
      ContentControlMain.Content = New ContetUserEntry()
      ChangeRibbonTabVisibility(senderName)
      Exit Select
    Case "MenuUserList"
      ContentControlMain.Content = New ContetUserList()
      ChangeRibbonTabVisibility(senderName)
      Exit Select
  End Select
End Sub

Private Sub ChangeRibbonTabVisibility(ByVal senderName As String)
  If senderName = "MenuObentoOrder" Then
    TabObentoOrder.Visibility = Visibility.Visible
  End If
  If senderName = "MenuObentoEntry" Then
    TabObentoEntry.Visibility = Visibility.Visible
  End If
  If senderName = "MenuObentoList" Then
    TabObentoList.Visibility = Visibility.Visible
  End If
  If senderName = "MenuUserEntry" Then
    TabUserEntry.Visibility = Visibility.Visible
  End If
  If senderName = "MenuUserList" Then
    TabUserList.Visibility = Visibility.Visible
  End If

  If senderName <> "MenuObentoOrder" Then
    TabObentoOrder.Visibility = Visibility.Hidden
  End If
  If senderName <> "MenuObentoEntry" Then
    TabObentoEntry.Visibility = Visibility.Hidden
  End If
  If senderName <> "MenuObentoList" Then
    TabObentoList.Visibility = Visibility.Hidden
  End If
  If senderName <> "MenuUserEntry" Then
    TabUserEntry.Visibility = Visibility.Hidden
  End If
  If senderName <> "MenuUserList" Then
    TabUserList.Visibility = Visibility.Hidden
  End If
End Sub

Private Sub Menu_Unchecked(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles MenuUserList.Unchecked, MenuUserEntry.Unchecked, MenuObentoList.Unchecked, MenuObentoEntry.Unchecked, MenuObentoOrder.Unchecked
  If ContentControlMain IsNot Nothing Then
    If (MenuObentoOrder.IsChecked = False) AndAlso
      (MenuObentoEntry.IsChecked = False) AndAlso
      (MenuObentoList.IsChecked = False) AndAlso
      (MenuUserEntry.IsChecked = False) AndAlso
      (MenuUserList.IsChecked = False) Then
      DirectCast(sender, ToggleButton).IsChecked = True
    End If
  End If
End Sub

各ToggleButtonコントロールのChecked/Uncheckedイベント・ハンドラの実装(上:C#、下:VB)

 コード内容の詳細は割愛するが、簡単に説明すると、クリックされたメニューを判定して、以前選択されていたメニューのチェック状態を解除し、さらにコンテンツ領域とリボン・タブの切り替えを行っている。

 以上で、前編で目標とする基本部分は完成した。

■応用的なUI開発

 今回のUIで気になるのは、選択されたメニューの外観が標準のボタンと変わらないところだ。そこでここでは、もう少しメニューらしい外観に変更してみよう。

メニュー・ボタンの外観の変更

 ここではToggleButtonコントロールの外観を変更する必要があるわけだが、このような場合、WPFでは「コントロール・テンプレート」という機能を用いる。

 具体的には、WPFデザイナなどで対象のToggleButtonコントロールを選択したうえで、[プロパティ]ウィンドウの[Template]プロパティの右クリック・メニューから[値をリソースに抽出]を実行する。これにより、[リソースの作成]ダイアログが表示されるので、[キー]欄に任意の名前(今回は「TemplateMenu」)と入力して[OK]ボタンをクリックする。

 これにより、XAMLコードの<r:RibbonWindow.Resources>要素内に<ControlTemplate>要素が追加されるので、これを例えば下記のように書き換えればよい。

<LinearGradientBrush x:Key="BackgroundMenuMouseOver"
                     EndPoint="0.5,1" StartPoint="0.5,0">
  <GradientStop Color="#FFF7F7F7" Offset="0" />
  <GradientStop Color="#FFABABAB" Offset="1" />
</LinearGradientBrush>

<ControlTemplate x:Key="TemplateMenu" TargetType="ButtonBase">
  <my:ButtonChrome Background="{TemplateBinding Control.Background}" BorderBrush="{TemplateBinding Control.BorderBrush}" Name="Chrome" RenderDefaulted="{TemplateBinding Button.IsDefaulted}" RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}" RenderPressed="{TemplateBinding ButtonBase.IsPressed}" SnapsToDevicePixels="True">
    <ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" Margin="{TemplateBinding Control.Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" />
  </my:ButtonChrome>
  <ControlTemplate.Triggers>
    <Trigger Property="UIElement.IsKeyboardFocused" Value="True">
      <Setter Property="my:ButtonChrome.RenderDefaulted" TargetName="Chrome" Value="True" />
    </Trigger>
    <Trigger Property="UIElement.IsEnabled" Value="False">
      <Setter Property="Control.Foreground" Value="#FFADADAD" />
    </Trigger>

    <!--IsMouseOverを追加。IsCheckedを修正。-->
    <Trigger Property="UIElement.IsMouseOver" Value="true">
      <Setter Property="my:ButtonChrome.RenderMouseOver" TargetName="Chrome" Value="false" />
      <Setter Property="Control.Background" TargetName="Chrome" Value="{StaticResource BackgroundMenuMouseOver}" />
      <Setter Property="Control.Foreground" Value="Orange" />
      <Setter Property="Control.FontWeight" Value="Bold" />
    </Trigger>
    <Trigger Property="ToggleButton.IsChecked" Value="True">
      <Setter Property="my:ButtonChrome.RenderPressed" TargetName="Chrome" Value="false" />
      <Setter Property="Control.Background" TargetName="Chrome" Value="Indigo" />
      <Setter Property="Control.Foreground" Value="White" />
      <Setter Property="Control.FontWeight" Value="Bold" />
    </Trigger>

  </ControlTemplate.Triggers>
</ControlTemplate>

コントロール・テンプレートによる外観のカスタマイズ(XAML)
コード中のmy名前空間は、コントロール・テンプレートのコードが自動生成された際に自動追加されたもの。具体的には、<r:RibbonWindow>要素に「xmlns:my="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"」のような記述で定義されている。

 こちらもコード内容の詳細は割愛するが、簡単に説明すると、<Trigger Property="UIElement.IsMouseOver" Value="true">要素や<Trigger Property="ToggleButton.IsChecked" Value="True">要素内で各種プロパティを設定している。ポイントは、下記のコードによるプロパティ設定で「false」を設定しているところだ。こうしないと、デフォルトのレンダリング処理により、背景色などのプロパティが正常に動作しない。

<Setter Property="my:ButtonChrome.RenderMouseOver" TargetName="Chrome" Value="false" />
<Setter Property="my:ButtonChrome.RenderPressed" TargetName="Chrome" Value="false" />

 以上でコントロール・テンプレートの作成は完了したので、ほかのToggleButtonコントロールにも適用する。一括で適用するには、[ドキュメント アウトライン]ウィンドウで[Ctrl]キーを押したまま、各ToggleButtonコントロールを次々とクリックして選択したうえで、[プロパティ]ウィンドウの[Template]プロパティの右クリック・メニューから[リソースの適用]を実行する。次の画面のように表示されるので、先ほど作成したコントロール・テンプレートを選択すればよい。

コントロール・テンプレートの適用([プロパティ]ウィンドウ)

 ここでビルドして実行したのが次の画面だ。

リッチになったメニューの表示 <</font>
例外が発生すると、IntelliTraceの実行履歴が[IntelliTrace]ウィンドウに表示される。

 ここまでに作成したサンプル・プログラムのソース・コードは下記のリンクからダウンロードできる。


 今回はここまでとする。次回は、データベース関係の処理を実装する。

「特集:Visual Studio 2010で社内C/Sシステム開発」のインデックス

特集:Visual Studio 2010で社内C/Sシステム開発

前のページへ 1|2|3       

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

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

メールマガジン登録

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