본문 바로가기
인생은 실전/C#

[WPF] Data Binding - ④ : MVVM 형태로 KeyDown 이벤트 사용하기 / ICommand / InputBindings

by 나는영하 2023. 6. 24.

 Data Binding - ④ : MVVM 형태로 KeyDown 이벤트 사용하기

 

윈폼에서 Event를 처리하는 방법은 매우 간단합니다.

Event를 처리하고자 하는 컨트롤에 Event를 연결하고 비하인드 코드에서 이벤트가 호출되면 처리하는 코드를 구현하면 되기 때문입니다.

 

하지만 WPF의 MVVM 형태로 따른다면 View의 비하인드 코드부에는 별다른 코드가 없고 ViewModel과의 바인딩을 통해 Event를 처리해야 합니다.

 

2022.11.25 - [인생은 실전/C#] - [WPF] Data Binding - ① : 데이터 바인딩(Data Binding) 기초 / 데이터 컨텍스트(Data Context) 속성

 

[WPF] Data Binding - ① : 데이터 바인딩(Data Binding) 기초 / 데이터 컨텍스트(Data Context) 속성

Data Binding-① : 데이터 바인딩 기초 및 데이터 컨텍스트 속성 사용 본문은 https://www.wpftutorial.net/ 의 내용을 본인이 해석하고 별도로 관련 정보를 찾아서 정리하였습니다. 원본은 위의 링크를 참고

920416.tistory.com

간단한 속성값(string, bool, int) 등을 바인딩 하기 위해서는 INotifyPropertyChanged 인터페이스를 상속받아서 처리하면 되지만 어떠한 동작, 행동(Click, KeyDown, MouseLeave 등..)을 바인딩 하기 위해서는 ICommand 라는 인터페이스를 상속받아서 처리해야 합니다. 

 

ICommand라는 인터페이스를 상속받아서 RelayCommand라는 클래스를 만들어 특정 동작(이벤트)을 처리하는 인터페이스를 구현하고, ViewModel에 RelayCommand를 인스턴스화 하여 객체로 선언하고 View에 바인딩을 걸어서 MVVM형태로 KeyDown 이벤트를 처리해 보도록 하겠습니다. 

 

 1. RelayCommand.cs (ICommand 상속)

 

제네릭 클래스 Class<T> 사용

제네릭 클래스(Class<T>)를 사용해서 Command 명령어를 통해 받을 멤버 변수의 타입이 어떤것이 오든 상관없도록 하였습니다. 제네릭을 사용하지 않는다면 CommandParameter를 사용하지 않는 것이고, 별도로 Event를 처리할때 View에서 특정한 파라미터를 넘겨받지 않음을 의미합니다. 

 

아래의 코드는 인터넷에 흔히 떠도는 ICommand 인터페이스를 상속받아서 Command 속성에 바인딩하여 처리하기 위한 클래스 입니다. 해당 클래스에 대한 설명은 다른 정리 되어 있는글이 더 많으니 생략하겠습니다😂

 public class RelayCommand<T> : ICommand
    {
        private readonly Action<T> mExecute = null;
        private readonly Predicate<T> mCanExecute = null;

        public RelayCommand(Action<T> execute)
          : this(execute, null)
        {
        }

        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
        {
            this.mExecute = execute ?? throw new ArgumentNullException("execute");
            this.mCanExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (this.mCanExecute != null)
                    CommandManager.RequerySuggested += value;
            }

            remove
            {
                if (this.mCanExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }
        
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return this.mCanExecute == null ? true : this.mCanExecute((T)parameter);
        }

        public void Execute(object parameter)
        {
            this.mExecute((T)parameter);
        }
    }

 

대략적으로 CanExcute가 해당 Command 속성에 바인딩 된 메서드를 호출할 수 있는 상태인지를 파악하는 부분이며 true를 반환하면 Excute 메서드가 호출 가능한 상태라고 보시면 됩니다.  

 

 

 2. View (Serial.xaml)

✅ TextBox.InputBindings 태그

TextBox의 하위 태그인 InputBindings을 통해 각 Key에 대해 바인딩을 걸어야 합니다.

KeyBinding 태그의 Key속성의 값으로 Enter를 입력해주면 키보드의 Enter에 대한 KeyDown 이벤트와 동일한 개념이라고 생각하시면 됩니다. 

그리고 해당 Command에 특정한 인자를 넘기기 위해 CommandParameter 속성을 사용하였고, TextBox의 Text를 해당 Command의 전달인자로 설정하였습니다.

<TextBox Name="tbMsg"
         Margin="20,0,0,0"
         Width="650"
         VerticalAlignment="Center"
         Style="{StaticResource MaterialDesignTextBoxBase}"
         Foreground="{DynamicResource PrimaryTextColor}"
         BorderBrush="{DynamicResource PrimaryIconColor}"
         Text="{Binding Path=TbText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <TextBox.InputBindings>
            <KeyBinding Key="Enter"
                        Command="{Binding EnterKeyDown}"
                        CommandParameter="{Binding ElementName=tbMsg, Path=Text}"/>
    </TextBox.InputBindings>
</TextBox>

 

 

 3. ViewModel (SerialViewModel.cs)

✅ RelayCommand 객체를 사용하여 프로퍼티 구성

Set을 할 경우는 없으니 set 부분은 지워주고, get 부분에 ??연산자를 사용함으로써 RelayCommand를 객체로 만든enterKeyDown이 null이라면 오른쪽EnterKeyDownEvent 매서드를 호출하도록 하였습니다. 

private RelayCommand<object> enterKeyDown;
public RelayCommand<object> EnterKeyDown
{
    get
    {
        return (this.enterKeyDown) ?? (this.enterKeyDown = new RelayCommand<object>(new Action<object>(EnterKeyDownEvent)));
    }
}

 

✅ ViewModel에 KeyDownEvent 코드 구현

RelayCommand 객체의 get에 걸어둔 메서드를 ViewModel에서 구현해 줍니다.

RelayCommand를 제네릭 클래스로 만들었기 매개변수의 갯수만큼 해당 메서드의 파라미터를 지정해줍니다. 

private void EnterKeyDownEvent(object message)
{
    //KeyDown Event 처리부분 구현 

}

 

결과

UI : TCP 통신 화면

하단의 TextBox에 입력한 글자가 전달인자가 되어서 Enter를 누르면 Command에 바인딩 되고 KeyDownEvent가 동작되도록 구현하였습니다.(TCP 통신을 통해 Listener에 Message 전달)

 

Enter키에 대해 바인딩 된 메서드

RelayCommand 객체를 통해 TextBox의 InputBindings 태그에 바인딩한 메서드의 전달인자를 확인해보면 사용자가 TextBox에 타이핑한 Text가 그대로 전달인자가 되어서 해당 메서드의 파라미터가 된 것을 알 수 있습니다. 

 

댓글