Вводная
Предположим, что имеется у нас самодельная RoutedUICommand, которая объявляется, например, так :
public partial class k4Command {
private static RoutedUICommand _ВаритьСуп;
public static RoutedUICommand ВаритьСуп { get { return _ВаритьСуп; } }
public static string ВаритьСуп_KeyGestureDisplayString { get; set; }
public static KeyGesture ВаритьСуп_KeyGesture { get; set; }
static k4Command() {
ВаритьСуп_KeyGestureDisplayString = "Ctrl-F1";
ВаритьСуп_KeyGesture = new KeyGesture(
key : Key.F1,
modifiers : ModifierKeys.Control,
displayString: ВаритьСуп_KeyGestureDisplayString );
_ВаритьСуп = new RoutedUICommand(
text : "ВаритьСуп", // "текст-показываемый-в-UI"
name : "ВаритьСуп", // "внутреннее-имя-команды"
ownerType : typeof( k4Command ), // "класс-владелец-команды"
inputGestures: new InputGestureCollection() { ВаритьСуп_KeyGesture } // "манипуляции-для-вызова"
);
}
}
используется в хамле так:
<Window.Resources>
<local:k4Commands x:Key="k4commands" />
<CommandBinding x:Key="cmd_ВаритьСуп"
Command="{x:Static local:k4command.ВаритьСуп}"
Executed="cmd_ВаритьСуп_Execute"
CanExecute="cmd_ВаритьСуп_CanExecute" />
</Window.Resources>
<Window.CommandBindings>
<StaticResource ResourceKey="cmd_ВаритьСуп"/>
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding
Key="{Binding Source={StaticResource k4commands}, Path=ВаритьСуп_KeyGesture.Key}"
Modifiers="{Binding Source={StaticResource k4commands}, Path=ВаритьСуп_KeyGesture.Modifiers}"
Command="local:k4Command.ВаритьСуп" />
</Window.InputBindings>
<Button
Name = "button_ВаритьСуп"
Command="{x:Static local:k4Commands.ВаритьСуп}"
Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"
/>
и связана с обработчиками, например, такими:
//==============================================
public void cmd_ВаритьСуп_CanExecute( object sender, CanExecuteRoutedEventArgs e ) {
if( имеетсяПлита && имеетсяВПлитеГаз && имеетсяКастрюля && имеетсяВода && имеютсяВсякиеДругиеИнгридиенты )
e.CanExecute = true; // имеем возможность варить суп
else
e.CanExecute = false; // не имеем возможности варить суп
}
//----------------------------------------------
public void cmd_ВаритьСуп_Execute( object sender, ExecutedRoutedEventArgs e ) {
ТакиВаримНемедленноСуп();
}
//----------------------------------------------
а требуется по логике работы ко всей этой красоте добавить еще и такой обработчик:
//----------------------------------------------
private void cmd_ВаритьСуп_PreviewExecuted( object sender, ExecutedRoutedEventArgs e ) {
if ( хотимЛиВообщеПитатьСвоиТаланты )
e.Handled = false; // продолжим исследование вопроса
else
e.Handled = true; // незачем напрягаться
}
//----------------------------------------------
Грабли-1
(мало)известный медицинский факт, что если мы захотим прицепить обработчик PreviewExecuted штатным образом :
<CommandBinding x:Key="cmd_ВаритьСуп"
Command="{x:Static local:k4command.ВаритьСуп}"
Executed="cmd_ВаритьСуп_Execute"
CanExecute="cmd_ВаритьСуп_CanExecute"
PreviewExecuted = "cmd_ВаритьСуп_PreviewExecuted" />
то обрабтчик Executed у нас не будет вызван никогда-и-ни-за-какие-деньги.
связано это с особенностями обработки команд, объявленных внутри <Window.CommandBindings>
"понять это нельзя, это можно только запомнить..."(c)
Костыль
НО! Существует (еще-менее)известный медицинский факт, что логичное поведение подобного рода таки реализовать можно, если привязывать обработчик PreviewExecuted напрямую к UI-элементу посредством такого вызова:
CommandManager.AddPreviewExecutedHandler( button_ВаритьСуп, ВаритьСуп_PreviewExecuted );
и все бы хорошо, но у нас имеется маааленькое исключение...
Грабли-2
... KeyBinding у нас является допустимым ICommandSource, но ни-разу-не-является UI-элементом и как параметр этой функции использован быть не может. А хочется...
Собственно Вопрос:
Существует хоть-сколько-нибудь-штатный способ прицепить обработчик PreviewExecuted к KeyBinding-у?