MVVM 패턴에서 KeyDown Event 처리 방법

안녕하세요.
MVVM 패턴으로 이것 저것 테스트 하다 조언을 좀 구합니다.

구현하고자 하는 것은,
메인창에서 키보드 이벤트(KeyDown) 받아서 Model을 변경하고,
Model이 변경될 때 View에 자동으로 반영되게 하려고 합니다.

키보드 이벤트를 받기 위해,
MainWindow.xaml 에서 KeyDown=“OnKeyDownHandler” 를 해줬고,
MainWindow.xaml.cs 파일에서 OnKeyDownHandler(object sender, KeyEventArgs e)를 구현해서
작동은 잘 됩니다.

이렇게 하면 MVVM 패턴이 아니라 기존 Winform 방식인것 같단 생각이 들어서요~

MVVM 패턴으로 하게되면 ModelView단에서 ICommand 방식으로 구현이 되어야 할 것 같다는 생각이 들어서요… ^^

3개의 좋아요

말씀하신 것처럼 Command를 직접 구현하셔도 되고, WPF 이신지는 모르겠으나, MVVM 프레임워크를 이용하시면 쉽게 이용 가능할 것 같습니다.

1개의 좋아요
ViewModel에 Command 만들어서 바인딩
 <TextBox>
      <TextBox.InputBindings>
           <KeyBinding Command="{Binding KeyDownCommand}" 
                       CommandParameter="{Binding Text, RelativeSource={RelativeSource AncestorType=TextBox, Mode=FindAncestor}}"
                       Key="KeyDown"/>
      </TextBox.InputBindings>
</TextBox>


또는 Behavior 처리.. 정도 하면 되겠네요
 <TextBox>
    <i:Interaction.Behaviors>
        <behavior:TextBoxBehavior />
    </i:Interaction.Behaviors>
</TextBox>
3개의 좋아요

저의 경우, 이벤트 동작 결과로 ViewModel의 데이터가 바뀐다면 Command를, 단순 UI 요소 변경이거나 조작일 경우에는 비하인드 코드에서 작성하고 있습니다.

MVVM이라고 해서 반드시 어디에다 작성하라는 정답은 없기에 본인이 판단해서 가장 적합하다고 생각하는 방법을 이용하면 될 것 같아요.,

3개의 좋아요

아직 MVVM 스터디 단계라~ 개념정리되면 프레임워크도 한번 찾아보겠습니다. 감사합니다. ^^

2개의 좋아요

제가 WPF 책을 본지 몇일 않되서요~

저같은 경우는 특정 텍스트박스가 아니라~
메인창에서 스페이스바 클릭 이벤트를 처리하고 싶은건데요…

MainWindows.xaml에서 <Window … KeyDown="{Binding OnKeyDownHandler}">
이런식으로 해줬습니다.
<Window 에서는 Command가 없더라고요~

public MainWindow() { InitializeComponent(); }
에서 DependencyObject의 DependencyProperty에서만 설정할수 있다고 오류가 나타나네요.

뭔가~
MVVM 패턴의 구조적인 부분의 이해가 더 필요할 것 같긴 한데요~ 감사합니다. ^^

1개의 좋아요

MVVM을 잘 몰라서 아직 판단기준이 명확하지 않아서요~ ^^

혹시,
비하인드코드 라는게, MainWindows.xaml.cs 파일을 말씀하시는거죠?

맞다면…
비하인드코드에서 바인딩된 모델 속성값을 직접 변경해주기도 하나요?

1개의 좋아요

View의 화면 동작을 ViewModel에 배치하는게 되려 맞지 않을 수 있습니다.

Window의 키 입력을 화면 동작이라고 정의한다면, 이벤트 핸들러로 처리해도 저는 상관이 없다고 생각합니다.

되려 키 이벤트 인자의 값들이 System.Window.Input에 속해 있어서 ViewModel의 인자로 전달하는것으로 옳지 않을 수 있습니다.

이런 관점에서 다음처럼 단순히 구현해봤습니다.
(저는 MVVM을 간단히 구현하기 위해 CommunityToolkit.Mvvm를 사용했습니다.

| MainWindow.xaml - Window의 KeyDown 이벤트를 핸들러로 처리

<Window
    x:Class="WpfKeyDownEventMVVM.MainWindow"
    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:i="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:local="clr-namespace:WpfKeyDownEventMVVM"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    KeyDown="Window_KeyDown"
    mc:Ignorable="d">
    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <Label Content="{Binding DownKey, Mode=OneWay}" FontSize="60" />
    </Grid>
</Window>

| MainWindow.xaml.cs - ViewModel 생성 및 이벤트를 ViewModel에 string으로 전달(종속성을 피하기 위함 실제로는 enum을 새로 정의해서 쓰면 좋음)

using System.Windows;
using System.Windows.Input;

namespace WpfKeyDownEventMVVM
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainWindowViewModel _viewmodel;

        public MainWindow()
        {
            InitializeComponent();

            _viewmodel = new MainWindowViewModel();
            DataContext = _viewmodel;
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            var key = e.Key.ToString();

            _viewmodel.DownKey = key;
        }
    }
}

| MainViewModel.cs - ViewModel에서 해당 키 처리 (이 코드에는 화면에 표시하기 위해 DownKey 속성을 이용 함

using CommunityToolkit.Mvvm.ComponentModel;

namespace WpfKeyDownEventMVVM
{
    [ObservableObject]
    public partial class MainWindowViewModel
    {
        [ObservableProperty]
        private string _downKey = string.Empty;
    }
}

| 실행화면 - 스페이스 키를 눌렀을 떄

실행되는 소스코드를 통해 코드 확인 및 실행해볼 수 있습니다.

6개의 좋아요
텍스트 박스는 샘플로 올려드린거 뿐입니다. 
MVVM기본패턴 구글링 하셔서 학습해 보시고 ViewModel에 Command를 생성해서 바인딩 하셔야 합니다.

<Window.InputBindings>
        <KeyBinding Key="Space" 
                    Command="{Binding ApplicationExitCommand}" 
                    CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"/>
    </Window.InputBindings>
2개의 좋아요

네 xaml.cs를 코드비하인드/비하인드코드 라고 부릅니다.

위에서 말씀하신 것들이 MVVM은 동작의 개념이라고 하더라도 View 컨트롤 위치를 바꾼다던가 데이터를 다루지 않는 요소는 ViewModel에 없어도 된다는 의미입니다. 이렇게만 해도 MVVM 위반이 아닙니다.

다만 취향에 따라 제로 코드비하인드 스타일을 추구하시는 분들은 계십니다.

4개의 좋아요

저는 제로코드 스타일을 추구하며 데이터를 다루지 않는 동작들은 Behavior처리하여 나중에 같은동작들은 Behavior를 재사용합니다

3개의 좋아요

샘플까지~ 감사합니다.^^

1개의 좋아요

네, 좀 더 찾아보겠습니다.
감사합니다.

2개의 좋아요