Silverlight 2でコンテキストメニューを表示する
Mike SnowsさんのブログでSilverlightでマウスの右クリックをフックする方法が紹介されていたので、やってみた。
普通はSilverlightコンテンツ上で右クリックすると「Silverlightの構成」というコンテキストメニューが表示されてしまうけど、これをDOMの「oncontextmenu」イベントをフックして表示させないようにするという技。
oncontextmenuイベントをフックするのは単純に「HtmlPage.Document.AttachEvent」メソッドを使ってイベントに関連付ければいい。
Page.xaml.cs
public Page() { InitializeComponent(); HtmlPage.Document.AttachEvent("oncontextmenu", OnContextMenu); } void OnContextMenu(object sender, HtmlEventArgs e) { e.PreventDefault(); }
でも、これだけではoncontextmenuイベントは呼び出されないのでSilverlightコンテンツをWindowlessモードにする必要がある。
Silverlightコンテンツの埋め込みにSilverlightコントロールを使っている場合はWindowlessプロパティをtrueに設定すればいい。
Default.aspx
<asp:Silverlight ID="Xaml1" runat="server" Windowless="true" Source="~/ClientBin/Debug/SilverlightApplication2.xap" MinimumVersion="2.0.30523" Width="100%" Height="100%" />
生のHTMLの場合はparamタグで指定する。
<object type="application/x-silverlight-2-b2" data="data:application/x-silverlight-2-b2," id="Xaml1" style="height:100%;width:100%;"> <param name="MinRuntimeVersion" value="2.0.30523"></param> <param name="Windowless" value="True"></param> <a href="http://go2.microsoft.com/fwlink/?LinkID=114576&v=2.0"> <img src="http://go2.microsoft.com/fwlink/?LinkID=108181" alt="Microsoft Silverlight を取得" style="border-width:0;" /> </a> </object>
これで「Silverlightの構成」というメニューを表示させないようにすることができる。
コンテキストメニューを表示する
せっかくなのでこれを利用して独自のコンテキストメニューを表示してみた。
まずはXAML側
Page.xml
<UserControl x:Class="SilverlightApplication2.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <UserControl.Resources> <Style x:Key="menuItem" TargetType="Button"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid Height="20"> <Border CornerRadius="4" BorderThickness="1"> <Border.Background> <LinearGradientBrush x:Name="brush" StartPoint="0.5,0" EndPoint="0.5,1"> <GradientStop Color="White" Offset="0" /> <GradientStop x:Name="background" Color="White" Offset="0.45" /> </LinearGradientBrush> </Border.Background> <Border.BorderBrush> <SolidColorBrush x:Name="border" /> </Border.BorderBrush> </Border> <ContentPresenter VerticalAlignment="Center" Margin="4,0,0,0" /> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonState"> <VisualState x:Name="Normal" /> <VisualState x:Name="MouseOver"> <Storyboard> <ColorAnimation To="Orange" Duration="0:0:0" Storyboard.TargetName="background" Storyboard.TargetProperty="Color" /> <ColorAnimation To="Orange" Duration="0:0:0" Storyboard.TargetName="border" Storyboard.TargetProperty="Color" /> <DoubleAnimation To="0.65" Duration="0:0:0" Storyboard.TargetName="brush" Storyboard.TargetProperty="Opacity" /> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White" MouseLeftButtonDown="LayoutRoot_MouseLeftButtonDown"> <Popup x:Name="contextMenu"> <Border Width="120" Height="64" BorderBrush="Silver" BorderThickness="1"> <StackPanel Margin="1"> <Button Content="コピー" Click="Button_Click" Style="{StaticResource menuItem}" /> <Button Content="貼り付け" Click="Button_Click" Style="{StaticResource menuItem}" /> <Button Content="切り取り" Click="Button_Click" Style="{StaticResource menuItem}" /> </StackPanel> </Border> </Popup> </Grid> </UserControl>
コードビハインド側
Page.xaml.cs
using System; using System.Windows; using System.Windows.Input; using System.Windows.Browser; using System.Windows.Controls; namespace SilverlightApplication2 { public partial class Page : UserControl { public Page() { InitializeComponent(); HtmlPage.Document.AttachEvent("oncontextmenu", OnContextMenu); } void OnContextMenu(object sender, HtmlEventArgs e) { e.PreventDefault(); contextMenu.HorizontalOffset = e.OffsetX; contextMenu.VerticalOffset = e.OffsetY; contextMenu.IsOpen = true; } private void Button_Click(object sender, RoutedEventArgs e) { contextMenu.IsOpen = false; HtmlPage.Window.Alert( string.Format("{0} click!", ((Button)sender).Content.ToString()) ); } private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { contextMenu.IsOpen = false; } } }
やってることは単純なことなので解説は割愛。
Windowlessにすることがどれくらいの影響があるのかわからないけど、問題が無ければこのテクニックを使ってもいいと思う。