KeyDown в Silverlight не работает с первого раза

WPF, MVVM, Silverlight | создано: 16.11.2010 | опубликовано: 16.11.2010 | обновлено: 13.01.2024 | просмотров: 5069

Написал приложение решил добавить пользователям удобства и сделал выбор варианта ответов на вопросы при помощи кнопок на клавиатуре, Чтобы можно было не только мышкой кликать. Причем всё это в MVVM. Долго мучился пока выяснил, что при нажатии на клавиши реакция есть, но только после того как кликнешь мышкой на приложении. Короче, пока приложение не получит фокус, кнопки не нажимаются. А решение этой проблемы очень простое, только есть некоторая изюминка.

Почему не нажимается кнопка

Понятно, что надо сделать так, чтобы при старте фокус был установлен как на плагин silverlight, так и на текущий контрол. В моем случаи это TrainingGameScreen, контрол, который является представлением (View). Надеюсь, приведенный код не требует пояснений:

    public partial class TrainingGameScreen : UserControl
    {
        public TrainingGameScreen()
        {
            InitializeComponent();
            Loaded += TrainingGameScreen_Loaded;
        }

        private void TrainingGameScreen_Loaded(object sender, RoutedEventArgs e)
        {
            System.Windows.Browser.HtmlPage.Plugin.Focus();
            this.Focus();
        }

    }

Обычно этого было достаточно и в предыдущей версии программы всё сработало как надо. А вот в новой версии, которая уже написана на NET 4.0 пришлось не мало повозиться, чтобы отыскать почему фокус не устанавливается. Оказывается, чтобы всё заработало именно так, как планировалось, надо установить в XAML у контрола верхнего уровня, например UserControl, свойство IsTabStop в True.

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:clb="http://schemas.calabonga.com/"
             xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
             x:Name="userControl"
             mc:Ignorable="d"
             IsTabStop="True">
                ...
        </UserControl>

Вот теперь реально всё правильно работает, и даже с первого раза. Вроде мелочь, а приятно!

Как нажать кнопку в MVVM

И в заключении статьи напиши, как нажатие кнопок обработать на стороне ViewModel. Тут неоценимую помощь мне оказала библиотека в которой есть EventToCommand, которая в свою очередь может принимать параметры и не просто, а параметры события привязки. В моем приложении уже есть команда, которые отрабатывают при нажатии на клик пользователя по кнопкам при выборе правильного ответа:

#region команда MakeAnswerCommand

/// <summary>
/// Команда MakeAnswerCommand обрабатывает нажатие пользователя на кнопку.
/// </summary>
public DelegateCommand<string> MakeAnswerCommand
{
    get
    {
        return new DelegateCommand<string>((e) => this.MakeAnswerCommandExecute(e));
    }
}

/// <summary>
/// Calabonga: Процедура выполняет команды MakeAnswerCommand
/// </summary>
private void MakeAnswerCommandExecute(string answer)
{
    // выполнение команды MakeAnswer
}

#endregion // end команда MakeAnswerCommand

Как видно из кода, команда принимает параметром строку, точнее букву выбранного варианта (A, B, C, D). Так вот, надо просто при нажатии на кнопки клавиатуры выполнить эту же команду, передав параметр выбора. Для этого в XAML подпишимся на событие KeyPress:

<UserControl
    ...
    ...>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="KeyDown">
            <clb:EventToCommand Command="{Binding MakeAnswerKeyDownCommand, Mode=OneWay}"
                                IsSendEventArgsToCommand="True" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <!-- много всякого кода -->
</UserControl>

Прошу заметить, что сия команда как параметр передает аргументы этого события во ViewModel. В данном случаи KeyEventArgsот KeyDown. Теперь осталось только добавить во ViewModel команду MakeAnswerKeyDownCommand, которая и будет обрабатывать переданные ей аргументы и выполнять другую команду описанную выше. Вот как выглядит эта команда:


#region команда MakeAnswerKeyDownCommand

/// <summary>
/// Calabonga: Команда MakeAnswerKeyDownCommand
/// </summary>
public DelegateCommand<KeyEventArgs> MakeAnswerKeyDownCommand
{
    get
    {
        return new DelegateCommand<KeyEventArgs>((e) => this.MakeAnswerKeyDownCommandExecute(e));
    }
}

/// <summary>
/// Calabonga: Процедура выполняет команды MakeAnswerKeyDownCommand
/// </summary>
private void MakeAnswerKeyDownCommandExecute(KeyEventArgs e )
{
    // выполнение команды MakeAnswerKeyDown
    switch (e.Key)
    {
        case Key.A:
            MakeAnswerCommand.Execute("C");
            break;
        case Key.Q:
            MakeAnswerCommand.Execute("A");
            break;
        case Key.S:
            MakeAnswerCommand.Execute("D");
            break;
        case Key.W:
            MakeAnswerCommand.Execute("B");
            break;
    }
}
#endregion // end команда MakeAnswerKeyDownCommand

Вот и всё, удачи в коде и вне его.