#c# #wpf #mvvm
#c# #wpf #mvvm
Вопрос:
Я внедряю простую Tetris
игру MVVM
. Основная панель есть Canvas
. Я хочу перемещаться с помощью стрелок клавиатуры. Для этого я реализовал MoveLeftCommand
и MoveRightCommand
. Команды привязаны к ViewModel
внутренней KeyBinding
части.
Ниже моя xaml
реализация
<Canvas
Width="{Binding Width}"
Height="{Binding Height}"
>
<Canvas.InputBindings>
<!-- One type of implementation -->
<KeyBinding Key="{Binding MoveLeftCommand.GestureKey}"
Command="{Binding MoveRightCommand}"/>
<!-- Different style of implementation -->
<KeyBinding Key="{Binding MoveLeftCommand.GestureKey}"
Command="{Binding MoveLeftCommand}"/>
</Canvas.InputBindings>
...
</Canvas>
Команды инициализируются в конструкторе ViewModel
«s».
public RelayCommand MoveRightCommand { get; set; }
public RelayCommand MoveLeftCommand { get; set; }
public GamePanelViewModel()
{
this.MoveLeftCommand = new RelayCommand(new Action(MoveLeft));
this.MoveLeftCommand.GestureKey = Key.Left;
this.MoveRightCommand = new RelayCommand(new Action(MoveRight));
this.MoveRightCommand.GestureKey = Key.Right;
}
И вот реализация команды:
public class RelayCommand : ICommand
{
private Action action;
public Key GestureKey { get; set; }
public RelayCommand(Action action) { this.action = action; }
public bool CanExecute(object parameter) { return true; }
public event EventHandler CanExecuteChanged;
public void Execute(object parameter) { this.action(); }
}
Soultion не работает.
В режиме отладки, когда я нажимаю клавишу со стрелкой влево или вправо, выполнение даже не входит CanExecute
в метод. Он ведет себя так, как если бы он не знал о командах.
Я также пытался принудительно сфокусироваться на Canvas
. Результата нет. Еще одна вещь, которую я пробовал, это реализовать команды по-другому. Результата тоже нет.
Однако, когда я добавил простой Textbox
поверх Canvas
, и реализовал те же команды на Textbox
, он начал работать — я мог перемещаться по игре с помощью стрелок.
Есть идеи, почему команды Canvas
были проигнорированы?
Спасибо
Комментарии:
1. Это потому
Canvas
, что не имеет фокуса клавиатуры. WPF начинается с сфокусированного элемента управления и поднимается вверх по визуальному дереву, чтобы увидеть, есть ли команда, которая обрабатывает этот жест. Например, включитеButton
вашCanvas
и сфокусируйте его, тогда он должен работать или делать что-то вроде<Canvas ... x:Name="myCanvas" Focusable="True">
и наWindow.Loaded
событии делатьmyCanvas.Focus();
2. Спасибо, настройка фокуса работает отлично. Я пытался заставить его раньше, но без настройки
Focusable = True
. Что касается первого решения, я понял трюк с другим элементом управления, но на мой вкус это было слишком сложно.
Ответ №1:
Я думаю, что ваша проблема возникает из-за простой проблемы инициализации.
Причина, по которой ничего не работает, заключается в том, что привязка произошла до создания объекта RoutedCommand .
замените свойства вашей команды следующей реализацией :
private RelayCommand moveRightCommand;
public RelayCommand MoveRightCommand
{
get
{
if (moveRightCommand == null)
{
moveRightCommand = new RelayCommand(MoveRight);
moveRightCommand.GestureKey = Key.Right;
}
return moveRightCommand;
}
}
В качестве альтернативы вы можете создать их так, как вы это делаете, и вызвать событие PropertyChanged в свойстве команды.
private RelayCommand moveRightCommand;
public RelayCommand MoveRightCommand
{
get
{
return moveRightCommand;
}
set
{
moveRightCommand = value;
PropertyChanged(this, new PropertyChangedEventArgs("MoveRightCommand"));
}
}
Комментарии:
1. Команды создаются в конструкторе до того, как возвращается указатель на
GamePanelViewModel
, поэтому он должен работать и будет работать, еслиCanvas
или что-то в нем будет иметь фокус клавиатуры.2. Я попробовал оба ваших предложения. К сожалению, ни то, ни другое не сработало.