Skip to content

[C# WPF] ContextMenuのCheckBoxをThreeStateで表示する

ContextMenuに3つの状態を遷移するチェックボックスを付けたくなりました。
標準のMenuItemはIsThreeStateを使用できなかったので、それっぽい動きをするものを自作しました。
CheckBoxと同様に、ContextMenuにもIsThreeStateを付けてくれればこんなことをしなくてもいいのですが。

具体的には、MenuItemを継承して状態フラグを追加したMenuItemを作っておいて、それに表示用のStyleをくっつけるだけです。

完成図

こんな感じに3パターンでチェックボックスを表示できます。

MenuItemを継承

Styleから参照できるように依存関係プロパティを追加するだけ。
ここではフラグをbool!で宣言しています。

/// チェックボックスで3つの状態を表示できるMenuItem
public class ThreeStateMenuItem : MenuItem
{
    /// MenuItemの状態の依存関係プロパテ意
    public static readonly DependencyProperty ThreeStateProperty =
        DependencyProperty.Register("ThreeState", typeof(bool?), typeof(ThreeStateMenuItem), new PropertyMetadata(false));

    /// MenuItemの状態のCLRプロパティ
    public bool? ThreeState
    {
        get { return (bool?)GetValue(ThreeStateProperty); }
        set { SetValue(ThreeStateProperty, value); }
    }
}

ThreeStateMenuItem用のスタイルを作成

3つの状態を表示するためのスタイルを作ります。
状態フラグをbool!型で宣言しているので、falseのときには非表示、trueのときにはチェック、nullのときにはハイフン、ということにしてあります。



    
    


動作を確認するために状態を切り替える処理を作る

こっちは主題ではないので適当にコンテキストメニューを開くたびに状態をひとつずつずらしていくようにしました。

まずはXaml。



    
    
        
            
            
                
                    
                    
                        
                    
                
            
            
            
        
    


コード。

/// 
/// MainWindow.xaml の相互作用ロジック
/// 
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    /// コンテキストメニューを開いた際に呼び出されるイベント
    private void WindowContextMenu_Opened(object sender, RoutedEventArgs e)
    {
        var menu = sender as ContextMenu;
        if (menu == null)
        {
            return;
        }

        foreach (ThreeStateMenuItem item in menu.Items)
        {
            // メニューを開くたびに状態をひとつ遷移する
            if (item.ThreeState == true)
            {
                item.ThreeState = false;
            }
            else if (item.ThreeState == false)
            {
                item.ThreeState = null;
            }
            else
            {
                item.ThreeState = true;
            }
        }
    }
}

おしまい。

Be First to Comment

コメントを残す

メールアドレスが公開されることはありません。

*

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください