Реализация сочетаний клавиш с командами-делегатами 

Когда я занимался реализацией сочетаний клавиш (например Ctrl+O) для своих команд-делегатов, то думал, что это должно быть элементарно, и будет сделано за пять минут. К сожалению, скоро стало ясно, что реализовать это гораздо труднее.

Я задал меню для моего приложения, аналогичное создаваемому в приведенном ниже фрагменте кода. Элемент меню "Open…" привязывает команду к свойству OpenCommand модели представления PresentationModel. Модель представления PresentationModel была установлена в качестве DataContext окна. До этого момента все прекрасно работало.

<Menu DockPanel.Dock="Top">
    <MenuItem Header="_File">
        <MenuItem Header="_Open..." Command="{Binding OpenCommand}" InputGestureText="Ctrl+O"/>
    </MenuItem>
</Menu>

Класс MenuItem имеет свойство с именем InputGestureText. Те, кто знаком с ToolStripMenu в Windows Forms, могут (как и я) подумать, что этого достаточно для задания в этом свойстве сочетания клавиш. Я узнал, что это свойство только показывает значение как дополнительный текст в пункте меню и никак не влияет на привязки клавиш WPF. Примечание. Свойство InputGestureText также необходимо локализовать.

Тогда я задал привязку клавиш для сочетания клавиш Ctrl+O следующим образом:

<Window.InputBindings>
    <KeyBinding Command="{Binding OpenCommand}"  Modifiers="Control" Key="O"/>
</Window.InputBindings>

Определение XAML выглядит правильно, но компилятор отображает ошибку, поскольку свойство Command класса KeyBinding не является свойством зависимостей (DependencyProperty), и в нем нельзя использовать привязку.

Я думал, что могу разрешить эту проблему, просто задав наследование моего класса "ShortCutKey" от класса KeyBinding и задав свойство зависимостей с именем "BindableCommand". Но это не работало, потому что классы KeyBinding не являются частью дерева элементов WPF (или визуального или логического дерева). По этой причине модуль привязки не может получить доступ к свойству DataContext окна, когда устанавливается PresentationModel.

Моя окончательная реализация довольно проста, но требует нескольких строк кода в классе кода программной части XAML.

<Window.InputBindings>
    <KeyBinding x:Name="openKeyBinding" Modifiers="Control" Key="O"/>
</Window.InputBindings>
public partial class ShellWindow : Window
{
    public ShellWindow()
    {
        InitializeComponent();
        DataContextChanged += ThisDataContextChanged;
    }
    private ShellPresentationModel PresentationModel { get { return DataContext as ShellPresentationModel; } }
    private void ThisDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        openKeyBinding.Command = PresentationModel.OpenCommand;
    }
}

В приведенном выше примере кода я прослушиваю событие DataContextChanged. Когда оно возникает, я знаю, что ShellPresentationModel была установлена, и я могу установить для свойства OpenCommand мою привязку клавиш. Это все. :-)