はじめに
Windowsフォームアプリケーションでおなじみのコンテキストメニューは、作業の手元でメニューがポップアップするため、とても使い勝手の良い機能ですが、残念ながらSilverlightの標準コントロールには用意されていません(WPFには標準で装備されています)。
ComponentOne Studio for Silverlightに収録されているC1ContextMenuコントロールは、Silverlightアプリケーション上でWindowsフォームのようにコンテキストメニューを使えるようにするコントロールで、コントロールごとにコンテキストメニューを組み込むことができます。今回は、このC1ContextMenuコントロールを使って、コントロールごとにコンテキストメニューを持ったWebページを作成してみました。
対象読者
Visual Basic/Visual C# 2008を使ってプログラムを作ったことのある人。また、SilverlightおよびXAMLに対する基礎的な知識が必要になります。
必要な環境
Visual Basic 2008、Visual C# 2008、Visual Studio 2008でプログラムが作れる環境。また、Visual Studio 2008 Silverlight Tools 3.0をインストールしていることが必須条件です。
なお、本プログラムはWindows Vista上で動作するVisual Studio 2008およびVisual Studio 2008 Silverlight Tools 3.0を使用して作成し、Internet Explorer 8で動作確認を行っています。
サンプルソースを実行するには、C#、VBともに次の設定を行う必要があるため、注意してください(※○○にはcsまたは vbのいずれかが入ります)。
- ソリューションエクスプローラでASP.NET Webサイトプロジェクト(sl_context_○○.Web)を右クリックし、[スタートアッププロジェクトに設定]を選択
- ソリューションエクスプローラで sl_context_○○TestPage.aspxを右クリックし、[スタートページに設定]を選択
コンポーネントのインストール
ComponentOne Studio for Silverlightを使用する方は、Visual Studio、Visual Basic、Visual C#の開発環境にComponentOne Studio Enterpriseをインストールする必要があります。
インストーラは、グレープシティのWebページからダウンロードできます。製品ページの[申込フォーム]をクリックし、グレープシティのWebサイトへ必要情報を登録すると、添付トライアルライセンスキーファイルとダウンロードサイトを記載したE-Mailが送られてきますので、ここからダウンロードします。制限事項などの詳細については、インストーラに同梱されているリリースノートを参照ください。
C1ContextMenuコントロールについて
C1ContextMenuコントロールを使用すると、Windowsフォームで良く利用されているコンテキストメニューと同様の機能を、Silverlightアプリケーションでも利用できます。また、他のコントロールに関連付けて使用することで、1つのWebページにコンテキストメニューをいくつでも組み込むことが可能です。
C1ContextMenuコントロールの実装方法
XAMLでC1ContextMenuコントロールを使うためには、メニューをポップアップさせたいコントロールの要素内に、C1ContextMenuコントロールを記述します。
その際、C1ContextMenuServiceクラスを使って、C1ContextMenuコントロールとそのコントロールを関連付けます。また、メニュー項目を設定する場合はC1MenuItemクラスを使用します。メニュー項目名は、C1MenuItemクラスのHeaderプロパティに設定します。
次の記述は、TextBoxコントロールにコンテキストメニューを設定したXAMLの記述例です。
<TextBox Width="300" Height="400">
<c1:C1ContextMenuService.ContextMenu >
<c1:C1ContextMenu x:Name="cmenu1" ItemClick="cmenu1_ItemClick">
<c1:C1MenuItem Header="コピー" >
</c1:C1ContextMenu>
</c1:C1ContextMenuService.ContextMenu>
</TextBox>
このように、TextBoxコントロールの中に「C1ContextMenuService」を、その中にC1ContextMenuコントロールを記述し、さらにその中に「C1MenuItem」を使ってメニュー項目を設定します。
また、メニュー項目にイメージ画像を設定することもできます。これは、C1MenuItemクラスのIconプロパティを使用します。
C1ContextMenuコントロールのデフォルトのイベントは「ItemClick」で、メニュー項目を選択すると発生します。選択したメニューの処理は、このイベントハンドラに設定します。
WindowlessプロパティをTrueに設定する
C1ContextMenuコントロールを使用するには、プラグインのWindowlessプロパティを「True」に設定する必要があります。この処理を行っておかないと、アプリケーション実行時にこのプロパティに関するエラーメッセージが表示されます。
ただし、コントロールがプラグインのプロパティを変更することはできないため、ページの作成者があらかじめWindowlessプロパティを「True」に設定しておきます。Windowlessプロパティは、プロジェクトにある「xxxTestPage.aspx」ファイル(xxxはアプリケーション名)に追加します。
ソリューションエクスプローラでこのファイル名をダブルクリックして開きます。
[ソース]タブをクリックするとコードが表示されます。
<body>セクションにある<param>セクションに、次のプロパティ設定を追加します。
<param name="Windowless" value="true" />
これで、Silverlightアプリケーションでコンテキストメニューを表示できるようになります。
Webページの作成
では、Webページを作成してみましょう。グリッドは1行2列に設定します。左側のグリッドにTextBoxコントロールを配置し、右側のグリッドにCanvasを配置して、グラフィックスオブジェクトの三角形を描画します。
Silverlightプロジェクトの作成
まず、Silverlightプロジェクトを作成します。Visual Studioで新しいプロジェクトを作成すると[プロジェクトの種類]に[Silverlight]が追加されています。これを選んで[テンプレート]から[Silverlightアプリケーション]を選択します。
「新しいSilverlightアプリケーション」というダイアログボックスが表示されるので、[新しいWebプロジェクトの種類]でリストから[ASP.NET Webサイト]を選びます。
プロジェクトが作成され、新しいWebサイトに「MainPage.xaml」が作られてXAMLのコードが表示されます。
TextBoxコントロールにコンテキストメニューを組み込む
まず、グリッドの左側に配置したTextBoxコントロールに、C1ContextMenuコントロールを使ってコンテキストメニューを組み込みます。
基本的なコンテキストメニューの作成
このコンテキストメニューには、以下の階層のメニュー項目を設定します。[ファイル]メニューは、いわゆるサブメニューで、この中に[開く][保存]の2つのメニュー項目を設定します。
-
ファイル
- 開く
- 保存
- 区切り線
- コピー
- 貼り付け
- 切り取り
今回は、[ファイル][開く][保存][コピー][貼り付け][切り取り]の6つのメニュー項目を設定します。まず、グリッドの中にTextBoxコントロールを作成し、その中にC1ContextMenuコントロールを作成します。この時、C1ContextMenuコントロールはツールボックスのアイコンをダブルクリックして作成してください。
<Grid x:Name="LayoutRoot" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox>
<c1:C1ContextMenu></c1:C1ContextMenu>
</TextBox>
</Grid>
すると、<c1:C1ContextMenu></c1:C1ContextMenu>のコードにエラーメッセージが出るので、この前後に「c1:C1ContextMenuService.ContextMenu」を入力します。C1ContextMenuServiceクラスはツールボックスにはないため、直接コードを入力します。
<TextBox>
<c1:C1ContextMenuService.ContextMenu>
<c1:C1ContextMenu></c1:C1ContextMenu>
</c1:C1ContextMenuService.ContextMenu>
</TextBox>
これで、C1ContextMenuServiceクラスによってTextBoxコントロールとC1ContextMenuコントロールが関連付けられます。後は、C1ContextMenuコントロールの中にC1MenuItemクラスを作成し、Headerプロパティにメニュー項目名を設定していきます。また、メニュー項目間に区切り線を入れたい場合は「C1Separator」を記述します。
<c1:C1ContextMenuService.ContextMenu >
<c1:C1ContextMenu >
<c1:C1MenuItem Header="ファイル..." >
</c1:C1MenuItem>
<c1:C1Separator />
<c1:C1MenuItem Header="コピー" >
</c1:C1MenuItem>
<c1:C1MenuItem Header="貼り付け" >
</c1:C1MenuItem>
<c1:C1MenuItem Header="切り取り" >
</c1:C1MenuItem>
</c1:C1ContextMenu>
</c1:C1ContextMenuService.ContextMenu>
[ファイル]メニューの下層のメニューの作成
[ファイル]メニューの下層にサブメニューを設定する場合は、このC1MenuItemタグの中にさらにC1MenuItemクラスを組み込んでいきます。ここでは[開く]と[保存]の2つのメニュー項目を組み込みます。
<c1:C1MenuItem Header="ファイル..." >
<c1:C1MenuItem Header="開く" >
</c1:C1MenuItem>
<c1:C1MenuItem Header="保存" >
</c1:C1MenuItem>
</c1:C1MenuItem>
より深い階層のメニューを作る場合は、さらにC1MenuItemクラスをネストしていきます。
メニュー項目にイメージを組み込む
メニュー項目にイメージを組み込む場合は、C1MenuItemクラスのIconプロパティにイメージファイルを設定します。この場合、プロジェクトの「ClientBin」フォルダにイメージファイルを追加し、Imageコントロールを使って組み込みます。
次のコードは[開く]メニューに「openHS.png」ファイルを設定し、16x16のサイズで表示します。
<c1:C1MenuItem Header="開く" >
<c1:C1MenuItem.Icon>
<Image Source="openHS.png" Width="16" Height="16"/>
</c1:C1MenuItem.Icon>
</c1:C1MenuItem>
ここでは、次のイメージファイルを各メニュー項目に設定しています。
| メニュー項目 | イメージファイル名 |
| 開く | openHS.png |
| 保存 | saveHS.png |
| コピー | CopyHS.png |
| 貼り付け | PasteHS.png |
| 切り取り | CutHS.png |
<Grid x:Name="LayoutRoot" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- TextBoxのコンテキストメニュー -->
<TextBox x:Name="text1" Grid.Column="0" AcceptsReturn="True" Width="300" Height="400"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
TextWrapping="Wrap" >
<c1:C1ContextMenuService.ContextMenu >
<c1:C1ContextMenu Foreground="Purple"
BorderBrush="SlateBlue" BorderThickness="2" >
<c1:C1MenuItem Header="ファイル..." >
<c1:C1MenuItem Header="開く" >
<c1:C1MenuItem.Icon>
<Image Source="openHS.png" Width="16" Height="16"/>
</c1:C1MenuItem.Icon>
</c1:C1MenuItem>
<c1:C1MenuItem Header="保存" >
<c1:C1MenuItem.Icon>
<Image Source="saveHS.png" Width="16" Height="16"/>
</c1:C1MenuItem.Icon>
</c1:C1MenuItem>
</c1:C1MenuItem>
<c1:C1Separator />
<c1:C1MenuItem Header="コピー" >
<c1:C1MenuItem.Icon>
<Image Source="CopyHS.png" Width="16" Height="16"/>
</c1:C1MenuItem.Icon>
</c1:C1MenuItem>
<c1:C1MenuItem Header="貼り付け" >
<c1:C1MenuItem.Icon>
<Image Source="PasteHS.png" Width="16" Height="16"/>
</c1:C1MenuItem.Icon>
</c1:C1MenuItem>
<c1:C1MenuItem Header="切り取り" >
<c1:C1MenuItem.Icon>
<Image Source="CutHS.png" Width="16" Height="16"/>
</c1:C1MenuItem.Icon>
</c1:C1MenuItem>
</c1:C1ContextMenu>
</c1:C1ContextMenuService.ContextMenu>
</TextBox>
</Grid>
メニューが選択された時の処理
続いて、メニューがクリックされた時の処理をコンテキストメニューに組み込みます。グリッドの右側にCanvasを配置し、ここにグラフィックスクラスのPolygonで三角形を描画します。そして、コンテキストメニューを設定し、描画した三角形を回転させます。
Canvasにコンテキストメニューを設定する
まず、XAMLでCanvas内にPolygonクラスを設定します。コードから操作するため、オブジェクトに名前を付けておきます。その下に、TextBoxコントロールの時と同じように、C1ContextMenuコントロールを設定します。TextBoxコントロールのコンテキストメニューとデザインを変え、メニュー項目の文字色とコンテキストメニューの枠線の色と太さを変えます。そして、イベントハンドラ「cmenu2_ItemClick」を設定します。
<Canvas Grid.Column="1">
<Polygon x:Name="poly1"
Points="300,200 400,125 400,275 300,200"
Stroke="Purple"
StrokeThickness="2">
<Polygon.Fill>
<SolidColorBrush Color="Blue" Opacity="0.4"/>
</Polygon.Fill>
</Polygon>
<c1:C1ContextMenuService.ContextMenu>
<c1:C1ContextMenu x:Name="cmenu2" ItemClick="cmenu2_ItemClick"
Foreground="Tomato"
BorderBrush="LimeGreen" BorderThickness="4" >
</c1:C1ContextMenu>
</c1:C1ContextMenuService.ContextMenu>
</Canvas>
C1MenuItemオブジェクトでメニュー項目を2つ作成します。メニューは「右45度」と「左45度」の2つで、それぞれイメージファイルを組み込みます。
<c1:C1MenuItem Header="右45度">
<c1:C1MenuItem.Icon>
<Image Source="cw.png" Width="16" Height="16"/>
</c1:C1MenuItem.Icon>
</c1:C1MenuItem >
<c1:C1MenuItem Header="左45度" >
<c1:C1MenuItem.Icon>
<Image Source="ccw.png" Width="16" Height="16"/>
</c1:C1MenuItem.Icon>
</c1:C1MenuItem >
イベントハンドラの処理
ビハインドコードのイベントハンドラ「ItemClick」では、2つのメニュー項目に合わせて三角形を回転させます。まず、グラフィックスオブジェクトを回転させる準備をします(詳しくはMicrosoft Silverlight デベロッパー センターを参照)。
次に、イベントハンドラの引数「e」の「Source」プロパティから、クリックされたメニュー項目を取得します。どのメニューがクリックされたのかは、このオブジェクトのHeaderプロパティを見れば分かるので、それぞれのメニューに合わせてグラフィックスオブジェクトの回転角を変えます。
Imports C1.Silverlight
...
...
Private Sub cmenu2_ItemClick(ByVal sender As System.Object, ByVal e As C1.Silverlight.SourcedEventArgs)
Dim rt As New RotateTransform
poly1.RenderTransform = rt
rt.CenterX = 300
rt.CenterY = 200
Dim item As C1MenuItem = e.Source
Select Case item.Header
Case "右45度"
rt.Angle = 45
Case "左45度"
rt.Angle = -45
End Select
End Sub
using C1.Silverlight;
...
...
private void cmenu2_ItemClick(object sender, C1.Silverlight.SourcedEventArgs e)
{
RotateTransform rt = new RotateTransform();
poly1.RenderTransform = rt;
rt.CenterX = 300;
rt.CenterY = 200;
C1MenuItem item = (C1MenuItem)e.Source;
string s = (String)item.Header;
switch(s)
{
case "右45度":
rt.Angle = 45;
break;
case "左45度":
rt.Angle = -45;
break;
}
}
まとめ
C1ContextMenuコントロールは、WindowsフォームのContextMenuコントロールを使ったことがあれば違和感なく使いこなせるので、XAMLによるオブジェクト設定さえ覚えれば、簡単にWebページに実装できます。使いやすいUIを求めている方は、ぜひ導入を検討してみてはいかがでしょうか。



![[ソース]タブをクリック](http://cz-cdn.shoeisha.jp/static/images/article/5918/5918_fig5.gif)


![[Silverlightアプリケーション]を選ぶ](http://cz-cdn.shoeisha.jp/static/images/article/5918/5918_fig8.gif)