Подтвердить что ты не робот

Пользовательская команда WPF в контекстном меню отключена до тех пор, пока не будет нажата любая кнопка

У меня есть пользовательская команда, и я пытаюсь выполнить их из контекстного меню, но они всегда отображаются как отключенные, если я не нажму кнопку на пользовательском интерфейсе (кнопки не имеют ничего общего с командами).

После нажатия кнопки команды начинают отображаться правильно (когда они недоступны, они становятся недоступными и включаются, если они доступны).

Редактирование: оказывается, что это не кнопка, которая заставляет команду работать правильно, но кнопка или другие элементы управления в фокусе (например, если я вставляю элемент управления, это также позволяет мои команды).

Вот код для команд:

<Window.InputBindings>
    <KeyBinding Command="{x:Static local:MainWindow.Quit}" Key="Q" Modifiers="Ctrl"/>
    <KeyBinding Command="{x:Static local:MainWindow.Disconnect}" Key="D" Modifiers="Ctrl"/>
</Window.InputBindings>

<Window.ContextMenu>
    <ContextMenu Opacity="95">
        <MenuItem Header="Quit Application                  Ctrl + Q"   Command="{x:Static local:MainWindow.Quit}"/>
        <MenuItem Header="Disconnect from the pump   Ctrl + D" Command="{x:Static local:MainWindow.Disconnect}"/>
    </ContextMenu>
</Window.ContextMenu>

Вот команды CanExecuteMethod:

public static RoutedCommand Quit = new RoutedCommand();   

private void QuitCanExecute(object sender, CanExecuteRoutedEventArgs e)
     {
      e.CanExecute = true;
      e.Handled = true;
     }
4b9b3361

Ответ 1

Полностью другой трек, теперь: есть действительно что-то особенное в ContextMenu в качестве носителя для команд: меню не рассматривается как часть окна и поэтому не ведет себя как элемент в его визуальном дереве.

Существуют различные решения для ваших проблем, определенных здесь: http://www.wpftutorial.net/RoutedCommandsInContextMenu.html

Самый простой подход, похоже, добавляет его в ваш XAML (для окна):

FocusManager.FocusedElement="{Binding RelativeSource={x:Static RelativeSource.Self}, Mode=OneTime}"

Ответ 2

Эта проблема связана с тем, что ContextMenu находится на отдельном Визуальном и Логическом дереве, чем в окне и его элемента управления.

Для тех, кто все еще ищет ответ на этот вопрос - после траления в Интернете я нашел наиболее эффективный ответ, чтобы включить следующее в любое объявление 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, чтобы изменить источник привязки к самому FrameworkElement, а не к DataContext. Таким образом, часть RelativeSource просто перемещает вас "на один уровень" из DataContext элемента FrameworkElement в сам элемент FrameworkElement. Когда вы находитесь в FrameworkElement, вы можете указать путь к любому из его свойств. Если FrameworkElement является всплывающим, он будет иметь свойство PlacementTarget, которое является другим элементом FrameworkElement, который всплывает по отношению к.

Короче говоря, если у вас есть Popup, размещенный относительно TextBox, например, это выражение устанавливает DataContext всплывающего окна в TextBox, и в результате {Binding Text} где-то в теле Popup будет привязываться к тексту текстового поля.

Я искренне надеюсь, что эта информация спасет тех, кто новичок в WPF, головную боль, которую я пережил в этот уик-энд... хотя это меня многому научило!

Ответ 3

Вероятно, есть некоторые изменения "за кулисами", которые обычно включали команды, но представление не знает об этом изменении. Нужно было бы увидеть Command-реализаций, чтобы дать более точные подсказки.

Вы можете либо сделать что-либо, что изменит ваше состояние включения команды, либо уведомить представление, либо вручную запустить обновление команды через CommandManager.InvalidateRequerySuggested(), например, когда откроется контекстное меню.

ICF файлы WPF работают именно так; они запрашивают свою функцию CanExecute всякий раз, когда что-то в представлении изменяется (например, событие PropertyChanged-событие запущено или нажимается кнопка), но они не требуют, чтобы у них не было причин.

Ответ 4

Я просто столкнулся с этим, пытаясь реализовать пользовательское контекстное меню для AvalonDock. Ни одно из предложенных выше решений не помогло мне.

Я получил контекстное меню, работая, явно регистрируя мои обработчики команд в классе ContextMenu в дополнение к главной вдове. Функция ниже - это помощник, который я использовал для регистрации команд.

    void RegisterCmd(RoutedCommand command, ExecutedRoutedEventHandler handler, CanExecuteRoutedEventHandler canExecute)
    {
        var binding = new CommandBinding(command, handler, canExecute);
        this.CommandBindings.Add(binding);
        CommandManager.RegisterClassCommandBinding(typeof(ContextMenu), binding);
    }