[WPF] Грабли с PreviewExecuted и KeyBinding
От: -ko4evnik-  
Дата: 17.01.11 18:30
Оценка:
Вводная
Предположим, что имеется у нас самодельная 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-у?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.