Когда вызывается CanExecute?
В демонстрации у меня есть кнопка для переключения поля bool isAsking
. Я создаю команду, которая может выполняться только тогда, когда isAsking==true
.
Как только я нажимаю кнопку Toggle, okButton.IsEnable
немедленно изменяется, что указывает, что команда находит изменение isAsking
.
Я очень смущен, почему объект команды замечает изменение поля, когда CanExecute
будет вызываться?
Несмотря на то, что я накладываю приложение WPF на некоторое время, я новичок в WPF Command. Просьба дать объяснение этому делу и, если возможно, указать некоторые связанные статьи или блоги (я уже читал слишком много статей о команде cut/paste).
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApplication1.MainWindow"
Title="MainWindow" Height="350" Width="525" x:Name="mainWindow" >
<StackPanel>
<Button Name="okButton" Content="Ok" />
<Button Content="Toggle" Click="Button_Click_1"/>
</StackPanel>
</Window>
Code-за:
public partial class MainWindow : Window
{
private bool isAsking;
public MainWindow()
{
InitializeComponent();
CommandBinding cb = new CommandBinding();
cb.Command = okCommand;
cb.CanExecute += CanOKExecute;
cb.Executed += cb_Executed;
mainWindow.CommandBindings.Add(cb);
okButton.Command = okCommand;
}
private RoutedCommand okCommand = new RoutedCommand("ok", typeof(MainWindow));
void cb_Executed(object sender, ExecutedRoutedEventArgs e)
{
}
void CanOKExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = isAsking;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
isAsking = !isAsking;
}
}
Ответы
Ответ 1
Я пытаюсь найти "CommandManager обнаруживает условия" и достигает этой замечательной статьи.
Изучая исходный код .NET Framework, автор обнаруживает, что CommandManager
не определяет условия сам по себе, а не когда Keyboard.KeyUpEvent
, Mouse.MouseUpEvent
, Keyboard.GotKeyboardFocusEvent
или Keyboard.LostKeyboardFocusEvent
происходит, это будет переоценить метод CanExecute.
В этой статье содержится другая информация, но для меня эта часть была достаточно.
Ответ 2
Технический ответ заключается в том, что CanExecute
будет вызываться всякий раз, когда возникает событие CommandManager.RequerySuggested
. Согласно документации, это будет...
... когда CommandManager обнаруживает условия, которые могут изменить возможность выполнения команды.
В практическом плане это просто означает, что вам не нужно беспокоиться о том, когда вызывается CanExecute
: WPF будет ссылаться на него, когда он считает, что это уместно, и по моему опыту это почти всегда будет отвечать вашим требованиям.
Исключением является то, что если у вас есть фоновая задача, которая заставит CanExecute
изменить его возвращаемое значение на основе чего-то, что не запускается пользовательским интерфейсом. В этом случае вам может потребоваться вручную заставить среду выполнения WPF повторно запросить CanExecute
, которую вы можете сделать, вызвав CommandManager.InvalidateRequerySuggested
Ответ 3
RoutedCommand
содержит событие CanExecuteChanged
, которое внутренне привязывается к событию CommandManager.RequerySuggested
-
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
Истекло событие CommandManager.RequerySuggested
всякий раз, когда изменения в источнике команд обнаруживаются командой менеджером, который в вашем случае является Window. Итак, когда кнопка нажата, commandManager поднял событие RequerySknown и, следовательно, выполнил предикат CanExecute, зарегистрированный для вашей команды.
Кроме того, CommandManager имеет статический метод - InvalidateRequerySuggested
, который заставляет CommandManager поднять RequerySovedEvent. Таким образом, вы можете вызвать это, чтобы проверить свои команды слишком вручную.