Windows ストアアプリでコンテキストメニューを実装する

PopupMenu.ShowForSelectionAsync(Rect) を使えば
XAML の定義など無しにコンテキストメニューを実装できます。

var menu = new PopupMenu();
menu.Commands.Add(new UICommand("コマンド1", (cmd) =>
{
    // クリックされたときに実行したい処理
}));
await menu.ShowForSelectionAsync(GetElementRect(element));// GetElementRect() は下記サンプル参照

表示できるコマンドは最大6つです。それ以上追加しようとすると実行時にエラーが出ます。

型 ‘System.Exception’ の例外が mscorlib.dll で発生しましたが、ユーザー コード内ではハンドルされませんでした
WinRT 情報: コンテキスト メニューに追加したメニュー項目が多すぎます。
追加情報: 有効な範囲外のデータにアクセスしようとしました


リツイートボタンのホールドまたは右クリック時に非公式リツイートのメニューを出すサンプル。
適宜 using を追加(赤の波下線が表示されてるクラス名で [Ctrl + .])してください。

// コンテキストメニュー
 
private async void ShowRetweetMenu(FrameworkElement element)
{
    var menu = new PopupMenu();
    menu.Commands.Add(new UICommand("非公式リツイート", (cmd) =>
    {
        // 非公式リツイートの処理
    }));
    await menu.ShowForSelectionAsync(GetElementRect(element));
}
 
private static Rect GetElementRect(FrameworkElement element)
{
    GeneralTransform buttonTransform = element.TransformToVisual(null);
    Point point = buttonTransform.TransformPoint(new Point());
    return new Rect(point, new Size(element.ActualWidth, element.ActualHeight));
}
 
// リツイートボタンのイベント
 
private void retweetButton_Tapped(object sender, TappedRoutedEventArgs e)
{
    // リツイートの処理
}
 
private void retweetButton_Holding(object sender, HoldingRoutedEventArgs e)
{
    if (e.HoldingState != HoldingState.Started) { return; }// Complete と Cancel は無視
 
    ShowRetweetMenu((FrameworkElement)sender);// (FrameworkElement)sender は e.OriginalSource as FrameworkElement でも良い
 
    e.Handled = true;
}
 
private void retweetButton_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
    if (e.PointerDeviceType != PointerDeviceType.Mouse) { return; }// タッチは Holding で処理するので無視
 
    ShowRetweetMenu((FrameworkElement)sender);
 
    e.Handled = true;
}
<Button x:Name="retweetButton"
    Tapped="retweetButton_Tapped"
    Holding="retweetButton_Holding"
    RightTapped="retweetButton_RightTapped"/>

Click にリツイートの処理を書くとホールド時も実行されてしまうので Tapped に。
コンテキストメニュー表示は Holding のスタート時のみ処理。
タッチ操作時は Holding の後に RightTapped も実行されるのでマウスのみに制御、
タッチ・マウス合わせて RightTapped だけでいいような気もしますがホールド時の UX を考えて分割。

【参考】
文字列のコピーをサポートするには?[Win 8]


カテゴリー: Windows ストア アプリ タグ: , , パーマリンク