質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.21%

[WPF][MVVM] ToggleButtonを押した時ContextMenuを表示したい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 368

Base

score 11

前提・実現したいこと

こんばんは。
WPF + Visual Studio2015にてトグルボタンのメニューを作成中です。

トグルボタンを押した時に、展開してメニューが表示するようにしたいです。
今は、押しても何もメニューが展開されない状態です。
ViewModelでの、フラグの切り替えは出来ていますが、ContextMenuを展開するのにはどうしたら良いのかを調べています。
 
色々調べましたが、情報を探し出せなかった為、ご教授頂けますと幸いです。

発生している問題・エラーメッセージ

ContextMenuのIsOpenが認識されない状態で、メニューが開かない状態。

該当のソースコード

    <Window.Resources>
        <local:BindingProxy x:Key="Proxy" Data="{Binding}" />
    </Window.Resources>

<Grid>
        <StackPanel>
            <Menu x:Name="menu" HorizontalAlignment="Left" Height="24" VerticalAlignment="Top" Width="519" Margin="0,0,-0.333,0">
                <MenuItem Header="ファイル">
                </MenuItem>
            </Menu>
        </StackPanel>
        <StackPanel>
            <ToolBar Margin="0,20,-0.333,0" Height="30">
                <ToggleButton IsChecked="{Binding ShowMeoDataOnly, Mode=TwoWay}">
                    <ToggleButton.ContextMenu>
                        <ContextMenu DataContext="{StaticResource Proxy}" IsOpen="{Binding Data.ShowMeoDataOnly, Mode=TwoWay}">
                            <MenuItem Command="{Binding Source={StaticResource Proxy}, Path=Data.MyCommand}">
                                <MenuItem.Header>
                                    <TextBlock Text="実行可能状態にする"/>
                                </MenuItem.Header>
                            </MenuItem>
                            <MenuItem Command="{Binding Source={StaticResource Proxy}, Path=Data.MyCommand}">
                                <MenuItem.Header>
                                    <TextBlock Text="移動する"/>
                                </MenuItem.Header>
                            </MenuItem>
                            <MenuItem Command="{Binding Source={StaticResource Proxy}, Path=Data.MyCommand}">
                                <MenuItem.Header>
                                    <TextBlock Text="ファイルから呼び出す"/>
                                </MenuItem.Header>
                            </MenuItem>
                        </ContextMenu>

                    </ToggleButton.ContextMenu>
                    <WrapPanel>
                        <StackPanel>
                            <TextBlock Text="操作内容" VerticalAlignment="Center" />
                        </StackPanel>
                        <!--<Path Width="10" Height="5" Stretch="Fill" Fill="Black" Data="F1 M0,0 L10,0 L5,10 Z " />-->
                        <Border Width="8" />
                    </WrapPanel>

                </ToggleButton>
            </ToolBar>

        </StackPanel>
    </Grid>
        private bool _ShowMeoDataOnly = false;
        public bool ShowMeoDataOnly
        {
            get
            {
                Console.WriteLine("Get Show Me Data >>" + _ShowMeoDataOnly);
                return _ShowMeoDataOnly;
            }
            set
            {
                if( _ShowMeoDataOnly != value)
                {
                    _ShowMeoDataOnly = value;

                    if(_ShowMeoDataOnly == true)
                    {
                        Console.WriteLine("Set Show Me Data >>  Open ");

                    }

                    base.RaisePropertyChanged(() => ShowMeoDataOnly);
                }
            }
        }
using System.Windows;

// BindingProxy.csを作成

    public class BindingProxy : Freezable
    {
        protected override Freezable CreateInstanceCore()
        {
            return new BindingProxy();
        }

        public object Data
        {
            get { return (object)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
    }

試したこと

1)原因は、下記のURLに乗っている事だというところまでは突き止めたが、
MVVM的にどうすれば良いか分からなかった。

https://social.msdn.microsoft.com/Forums/ja-JP/48ee254e-ac36-4fac-8df6-cbca000d19a6/contextmenu12434isopen1239138283123671239212467125101253112489123642?forum=wpfja

2)オリジナルで作る必要があるかと思い、下記を参考にしよう考えたが、
controls:CustomContextMenu の部分がどこからきているか、理解できなかった。

https://stackoverflow.com/questions/33688346/dynamically-create-contextmenu/33731677#33731677

よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Zuishin

    2019/04/14 20:38

    ・どのような手順を取るとどうなるようにしたいのか
    ・今はどうなるのか
    の二点についてわかりやすい説明があれば回答がつくかもしれません。
    その際、「認識」「反応」「うまくいかない」などの抽象的でわかりにくい言葉は避けてください。

    キャンセル

  • Base

    2019/04/15 08:57

    ありがとうございます。
    修正させて頂きました。
    よろしくお願いいたします。

    キャンセル

  • Zuishin

    2019/04/15 08:58

    ・どのような手順を取るとどうなるようにしたいのか
    ・今はどうなるのか
    の二点についてわかりやすい説明

    キャンセル

  • Zuishin

    2019/04/15 08:58

    があれば回答がつくかもしれません。
    長文すみませんでした。読みやすいように分けました。

    キャンセル

回答 2

checkベストアンサー

+1

PlacementTargetはDependencyPropertyなのでBindできますよ。

<ContextMenu IsOpen="{Binding ShowMeoDataOnly, Mode=TwoWay}" PlacementTarget="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton}}">


上記で、"一度右クリックで表示した後は"表示されるようになります。
一度右クリックで開かなくてはいけない理由と対策はこちらに書いてあります。ContextMenuをViewModelから開く方法

ちなみに、ShowMeoDataOnlyが両方TwoWayだとポップアップが閉じた時にToggleButtonまでoffになってしまうのですが、これは意図した動き(Menuのようにポップアップ開いている時だけ色を変えたい?)ですか?


昨日は上記だけでできていた気がしたのですが、今やってみたらできなくなっていました。なんでだろ。。。
Bindエラーが出ていてうまくBind出来ていないようなので、こちらにもBindingProxyを使ってやればよいと思います。

<ContextMenu DataContext="{StaticResource Proxy}" IsOpen="{Binding Data.ShowMeoDataOnly, Mode=TwoWay}">

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/16 11:51

    ありがとうございます。
    頂いた情報通りにコードを更新し見ました(上記コードを更新)
    しかし、、右クリックしないと動作しない状況です。。
    何か・・・自分のコードに問題があるのでしょうか・・・。

    ポップアップが閉じた時にToggleButtonまでoffになってしまう
     → これは意図した動きになっています。

    キャンセル

  • 2019/04/16 14:30 編集

    ありがとうございました。
    動作確認取れました。

    質問した際のソースコードが、最終動作コードになんります。

    キャンセル

+1

これってようするに、ToggleButtonがOnの間はContextMenuを開いた
ままにしておくってことですかね?
だとしたらIsOpenで制御するのは無理があるように思います。

素直にPopupにしたほうが良いのでは?

<Grid>
    <StackPanel>
        <Menu x:Name="menu" HorizontalAlignment="Left" Height="24" VerticalAlignment="Top" Width="519" Margin="0,0,-0.333,0">
            <MenuItem Header="ファイル">
            </MenuItem>
        </Menu>
    </StackPanel>
    <StackPanel>
        <ToolBar Margin="0,20,-0.333,0" Height="30">
            <ToggleButton IsChecked="{Binding ShowMeoDataOnly, Mode=TwoWay}">
                <!--<ToggleButton.ContextMenu>
                    <ContextMenu IsOpen="{Binding ShowMeoDataOnly, Mode=TwoWay}">
                        <MenuItem>
                            <MenuItem.Header>
                                <TextBlock Text="実行可能状態にする"/>
                            </MenuItem.Header>
                        </MenuItem>
                        <MenuItem>
                            <MenuItem.Header>
                                <TextBlock Text="移動する"/>
                            </MenuItem.Header>
                        </MenuItem>
                        <MenuItem>
                            <MenuItem.Header>
                                <TextBlock Text="ファイルから呼び出す"/>
                            </MenuItem.Header>
                        </MenuItem>
                    </ContextMenu>

                </ToggleButton.ContextMenu>-->
                <WrapPanel>
                    <StackPanel>
                        <TextBlock Text="操作内容" VerticalAlignment="Center" />
                    </StackPanel>
                    <Border Width="8" />
                </WrapPanel>

            </ToggleButton>
        </ToolBar>

        <Popup IsOpen="{Binding ShowMeoDataOnly, Mode=TwoWay}" Placement="MousePoint">
            <Border>
                <StackPanel Orientation="Vertical">
                    <MenuItem>
                        <MenuItem.Header>
                            <TextBlock Text="実行可能状態にする"/>
                        </MenuItem.Header>
                    </MenuItem>
                    <MenuItem>
                        <MenuItem.Header>
                            <TextBlock Text="移動する"/>
                        </MenuItem.Header>
                    </MenuItem>
                    <MenuItem>
                        <MenuItem.Header>
                            <TextBlock Text="ファイルから呼び出す"/>
                        </MenuItem.Header>
                    </MenuItem>
                </StackPanel>
            </Border>
        </Popup>

    </StackPanel>
</Grid>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/16 14:32

    ありがとうございます。
    もう一つの実現方法として、参考にさせて頂きました。

    今回は、自分のやりたい事にどんぴしゃだった、moredeep様の回答をベストアンサーに選ばせて頂きました。

    ご回答いただき、ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.21%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる