본문 바로가기

c#

c# WPF Behavior Grid click event mvvm패턴으로 만드는 법

wpf에서 Mvvm패턴을 지키면서 Grid에 클릭하는 방법입니다.

기존의 Grid는 Click 이벤트를 실행 할 수 없으나 Behavior를 사용하면 Grid에서도 클릭이벤트 사용이 가능합니다.

 

1.NuGet에서 Behaviors를 다운 받습니다.

 

2.xaml파일에 해당 문구를 넣어줍니다.

xmlns:i="http://schemas.microsoft.com/xaml/behaviors"

 

3.ViewModel 클래스에 Behavior 클래스를 상속합니다.

Behavior<지정할 컴포넌트 클래스> 이처럼 지정할 컨트롤 클래스를 명시해줍니다.

internal class GridBehavior : Behavior<Grid> 

 

4. OnAttached(),OnDetaching()를 구현합니다.

OnAttached를 통해 연결된 컨트롤 객체와 이벤트를 연결하고 

OnDetaching을 통해 이벤트를 해제 합니다.

    protected override void OnAttached()
        {
            //AssoicatedObject의 이벤트 핸들러 추가
            AssociatedObject.MouseDown += AssociatedObject_MouseDown;
        }

 

  protected override void OnDetaching()
        {
        	//이벤트 핸들러 삭제
            AssociatedObject.MouseDown -= AssociatedObject_MouseDown;
        }

 

5. 연결한 이벤트를 구현하여 실제로 실행될 로직을 입력합니다. 이때 Dispatcher를 사용해야 해당 스레드에 접근 가능합니다.

 private void AssociatedObject_MouseDown(object sender, System.Windows.Input.MouseEventArgs e)
        {  
        		//Dispatcher를 사용해야 해당 스레드에 접근할 수 있다.
                Dispatcher.BeginInvoke(DispatcherPriority.Background,(new Action(() => 
                {
                    System.Windows.Forms.MessageBox.Show("그리드 클릭");
                })));                   
        }

 

6.바인딩 시킬 객체를 생성합니다.

   public ICommand ClickCommand
        {
            get { return (ICommand)GetValue(ClickCommandProperty); }
            set { SetValue(ClickCommandProperty, value); }
        }

 

7. DependencyProperty를 사용하여 바인딩 해줍니다.

DependencyProperty는 Register를 통해 인스턴스와 클래스를 매핑하여 등록합니다.

 public static readonly DependencyProperty ClickCommandProperty =
            DependencyProperty.Register(nameof(ClickCommand), typeof(ICommand), typeof(GridBehavior), new PropertyMetadata(null));

 

8.xaml에 Interaction.Behaviors를 통해 xaml과 객체를 바인딩 시켜줍니다.

- 색상을 지정해야 클릭하는 이벤트가 제대로 실행되며 색상이 없으면 실행이 안됩니다.

<Grid Background="White">
        <i:Interaction.Behaviors>
            <local:GridBehavior ClickCommand="{Binding ClickCommand}" />
        </i:Interaction.Behaviors>
    </Grid>

 

그리드 클릭시 메세지가 제대로 나온다.

 

예제) xaml

<Window x:Class="WpfApp3.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp3" 
        xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
        mc:Ignorable="d"         
        Title="MainWindow" Height="450" Width="800">
    <Grid Background="White">
        <i:Interaction.Behaviors>
            <local:GridBehavior ClickCommand="{Binding ClickCommand}" />
        </i:Interaction.Behaviors>
    </Grid>
</Window>

예제) Behavior클래스

using Microsoft.Xaml.Behaviors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Threading;

namespace WpfApp3
{
    internal class GridBehavior : Behavior<Grid>
    {

        protected override void OnAttached()
        {
            //AssoicatedObject의 이벤트 핸들러 추가 - 삭제는 반드시 쌍으로 처리합니다.
            AssociatedObject.MouseDown += AssociatedObject_MouseDown;
        }

        private void AssociatedObject_MouseDown(object sender, System.Windows.Input.MouseEventArgs e)
        {
                Dispatcher.BeginInvoke(DispatcherPriority.Background,(new Action(() => 
                {
                    System.Windows.Forms.MessageBox.Show("그리드 클릭");
                })));                   
        }  

        protected override void OnDetaching()
        {
            AssociatedObject.MouseDown -= AssociatedObject_MouseDown;
        }

        public ICommand ClickCommand
        {
            get { return (ICommand)GetValue(ClickCommandProperty); }
            set { SetValue(ClickCommandProperty, value); }
        }

        public static readonly DependencyProperty ClickCommandProperty =
            DependencyProperty.Register(nameof(ClickCommand), typeof(ICommand), typeof(GridBehavior), new PropertyMetadata(null));
    }
}