7

現時点ではまだWPFをいじっていますが、このコンテキストメニュー項目が無効になっている理由がわかりません。

<Window x:Class="DisabledMenuItemProblem.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DisabledMenuItemProblem"
        Title="Window1" Height="300" Width="300">
    <TextBlock Text="fooooobaaaaaar">
        <TextBlock.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Foo" Command="{x:Static local:MyCommands.FooBar}" />
            </ContextMenu>
        </TextBlock.ContextMenu>
    </TextBlock>
</Window>

using System.Windows;
using System.Windows.Input;

namespace DisabledMenuItemProblem
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            CommandBindings.Add(new CommandBinding(MyCommands.FooBar, FooExecuted, CanFooExecute));
        }

        public void FooExecuted(object sender, ExecutedRoutedEventArgs e)
        { MessageBox.Show("Foo!"); }

        public void CanFooExecute(object sender, CanExecuteRoutedEventArgs e)
        { e.CanExecute = true; }
    }

    public static class MyCommands
    { 
        public static RoutedCommand FooBar = new RoutedCommand(); 
    }
}

私は何が欠けていますか?

また、私を困惑させているのは、ウィンドウにボタンを投げてそのコマンドをFooBarに設定すると、それが機能し、実行されると、コンテキストメニューが有効になることです。

乾杯、クリス。

4

5 に答える 5

11

ここに私が使用する一般的なパターンがあります....

まず、コマンドを独自の静的クラスに保持します。これにより、再利用が促進されます....

public static class MyCommands
{
    public static RoutedUICommand CmdFoo = new RoutedUICommand("CmdFoo", 
                                                               "CmdFoo", 
                                                               typeof(MyCommands));
}

次に、コマンドをコントロール/ウィンドウ/etc に登録します。通常はコンストラクターで使用します

public MyControl
{
    public MyControl()
    {
        CommandBindings.Add( 
            new CommandBinding( MyCommands.CmdFoo,   // this is the command object
                                XCutFooCommand,      // execute
                                CanXCuteFooCommand));// can execute?
    }

3番目に、コントロール/ウィンドウ/などでハンドラーを作成します.....

  public void CanExecuteRerollCommand(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;  // can this command be executed?
        e.Handled = true;     // has this event been handled?
    }
    public void ExecuteRerollCommand(object sender, ExecutedRoutedEventArgs e)
    {
    // do stuff
    }
}

最後に、xaml は次のようになります。

    <ContextMenu>
        <ContextMenu.CommandBindings>
            <CommandBinding Command="foo:MyCommands.CmdFoo" 
                            CanExecute="CanExecuteRerollCommand" 
                            Executed="ExecuteRerollCommand" />
        </ContextMenu.CommandBindings>
        <MenuItem Header="Reroll"  Command="foo:MyCommands.CmdFoo"/>
    </ContextMenu>

拘束力がないことに注意してください。の にも注目<CommandBinding>して<ContextMenu>ください。ここに参照があります.... http://www.wiredprarie.us/journal/2007/04/commandtarget_menuitem_context.html

無効になっているコマンドは、このサイトで対処されています

于 2009-01-19T05:51:09.537 に答える
8

この問題に対する答えを探している人のために-インターネットをトロールした後、「所有者」がコマンドを聞く必要があるMenuItemの宣言に次を含めることが最も効果的な答えであることがわかりました。

平たく言えば; コンテキスト メニューのコマンドを、右クリックしているものに聞かせたい場合。次のコードを追加します。

CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}"

例:

    <ContextMenu>
        <MenuItem Header="Close" Command="Application.Close" CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
    </ContextMenu>

これは、テンプレート内でも機能します (サポートされていない他の多くのソリューションが見つかりました)。これは、他の場所から取られたステートメントの意味の説明です(私は物事を説明するのが恐ろしいです):

すべての FrameworkElement には、任意のオブジェクトである DataContext があります。データ バインディングの既定のソースは、その DataContext です。RelativeSource.Self を使用して、バインドのソースをその DataContext ではなく FrameworkElement 自体に変更できます。したがって、RelativeSource 部分は、FrameworkElement の DataContext から FrameworkElement 自体に「1 レベル上」に移動するだけです。FrameworkElement に到達したら、そのプロパティのいずれかへのパスを指定できます。FrameworkElement が Popup の場合、Popup が相対的に配置される他の FrameworkElement である PlacementTarget プロパティを持ちます。

つまり、たとえば TextBox に対して相対的に配置された Popup がある場合、その式は Popup の DataContext を TextBox に設定し、その結果、Popup の本文のどこかに {Binding Text} が TextBox のテキストにバインドされます。 .

正直なところ、この情報が、WPF を初めて使用する人にとって、私が今週末経験した頭痛の種から解放されることを願っています。

スティーブ

于 2011-09-11T22:32:00.597 に答える
2

私が理解している限り、これは何が起こるかです。ContextMenu が表示されると、基本的に別のウィンドウであるポップアップに表示されます。ポップアップは、ウィンドウのメイン コンテンツと同じビジュアル ツリーに属していないため、コマンドはメイン ウィンドウに「バブル」しません。これが、CanExecute メソッドが呼び出されない理由です。たとえば、ContextMenu 自体に CommandBindings をアタッチすると、CanExecute が正しく呼び出されます。

ただし、特定の場合のポップアップは通常のウィンドウのように動作してはならず、特定のものが「バブル」する必要があることをどこかで読んだことを思い出します。

何らかの内部魔法が起こっているに違いないと思います。たとえば、単に TextBlock を TextBox に変更すると、うまくいくようです。Reflector は、TextEditorBase またはそのようなもので追加のロジックを表示するに違いありません。

本当に TextBlock を使用する必要がある場合は、ウィンドウではなく ContextMenu 自体に手動で CommandBinding を追加することになるでしょう。

于 2009-01-19T06:14:39.380 に答える
1

この問題を解決する最も簡単な方法は、コンテキスト メニューをウィンドウ リソースに移動し、そこから参照することです。

<ContextMenu x:Key="ControlContextMenu">
    <ContextMenu.CommandBindings>
        <CommandBinding Command="{StaticResource CloseCommand}" Executed="CloseExecuted" CanExecute="CloseCanExecute" />
    </ContextMenu.CommandBindings>          
    <MenuItem Command="{StaticResource CloseCommand}" />
</ContextMenu>

次に、UIElement で ContextMenu プロパティを設定するだけです

<TextBlock ContextMenu="{StaticResource ControlContextMenu}"/>
于 2013-09-25T15:34:54.813 に答える
0

さらに簡単な答えは、Window のコンストラクターにFocus()の呼び出しを追加することです。私は昨日この問題に遭遇し、何が起こっているのかを理解するのにかなりの時間を費やしました. ここでブログを書きました: http://cebla5.spaces.live.com/blog/cns!1B8262ED00250003!206.entry

ブログ投稿では、コンストラクターでのFocus()の呼び出しが機能する理由について説明します。

于 2009-02-18T07:11:59.503 に答える