첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형
728x170

TestProject.zip
다운로드

▶ CommandBehavior.cs

using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Input;

namespace TestProject
{
    /// <summary>
    /// 명령 동작
    /// </summary>
    public class CommandBehavior
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Class
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 이벤트 발생 어트리뷰트 - EventRaiseAttribute

        /// <summary>
        /// 이벤트 발생 어트리뷰트
        /// </summary>
        private class EventRaiseAttribute : Attribute
        {
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Dependency Property
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 이벤트 첨부 속성 - EventProperty

        /// <summary>
        /// 이벤트 첨부 속성
        /// </summary>
        public static readonly DependencyProperty EventProperty = DependencyProperty.RegisterAttached
        (
            "Event",
            typeof(string),
            typeof(CommandBehavior),
            new PropertyMetadata(EventPropertyChangedCallback)
        );

        #endregion
        #region 이벤트 핸들러 첨부 속성 - EventHandlerProperty

        /// <summary>
        /// 이벤트 핸들러 첨부 속성
        /// </summary>
        public static readonly DependencyProperty EventHandlerProperty = DependencyProperty.RegisterAttached
        (
            "EventHandler",
            typeof(Delegate),
            typeof(CommandBehavior)
        );

        #endregion
        #region 명령 첨부 속성 - CommandProperty

        /// <summary>
        /// 명령 속성
        /// </summary>
        public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached
        (
            "Command",
            typeof(ICommand),
            typeof(CommandBehavior),
            new PropertyMetadata(CommandPropertyChangedCallback)
        );

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 이벤트명 구하기 - GetEvent(d)

        /// <summary>
        /// 이벤트명 구하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <returns>이벤트명</returns>
        public static string GetEvent(DependencyObject d)
        {
            return d.GetValue(EventProperty) as string;
        }

        #endregion
        #region 이벤트명 설정하기 - SetEvent(d, eventName)

        /// <summary>
        /// 이벤트명 설정하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="eventName">이벤트명</param>
        public static void SetEvent(DependencyObject d, string eventName)
        {
            d.SetValue(EventProperty, eventName);
        }

        #endregion
        #region 이벤트 핸들러 구하기 - GetEventHandler(d)

        /// <summary>
        /// 이벤트 핸들러 구하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <returns>이벤트 핸들러</returns>
        public static Delegate GetEventHandler(DependencyObject d)
        {
            return d.GetValue(EventHandlerProperty) as Delegate;
        }

        #endregion
        #region 이벤트 핸들러 설정하기 - SetEventHandler(d, value)

        /// <summary>
        /// 이벤트 핸들러 설정하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="value">값</param>
        public static void SetEventHandler(DependencyObject d, Delegate value)
        {
            d.SetValue(EventHandlerProperty, value);
        }

        #endregion
        #region 명령 구하기 - GetCommand(d)

        /// <summary>
        /// 명령 구하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <returns>명령</returns>
        public static ICommand GetCommand(DependencyObject d)
        {
            return d.GetValue(CommandProperty) as ICommand;
        }

        #endregion
        #region 명령 설정하기 - SetCommand(d, command)

        /// <summary>
        /// 명령 설정하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="command">명령</param>
        public static void SetCommand(DependencyObject d, ICommand command)
        {
            d.SetValue(CommandProperty, command);
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Private

        #region 이벤트 속성 변경시 콜백 처리하기 - EventPropertyChangedCallback(d, e)

        /// <summary>
        /// 이벤트 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void EventPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BindEvent(d, e.NewValue as string);
        }

        #endregion
        #region 명령 속성 변경시 콜백 처리하기 - CommandPropertyChangedCallback(d, e)

        /// <summary>
        /// 명령 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void CommandPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion

        #region 이벤트 바인딩하기 - BindEvent(owner, eventName)

        /// <summary>
        /// 이벤트 바인딩하기
        /// </summary>
        /// <param name="owner">소유자 객체</param>
        /// <param name="eventName">이벤트명</param>
        private static void BindEvent(DependencyObject owner, string eventName)
        {
            if(string.IsNullOrWhiteSpace(eventName))
            {
                return;
            }

            EventInfo eventInfo = owner.GetType().GetEvent(eventName, BindingFlags.Public | BindingFlags.Instance);

            if(eventInfo == null)
            {
                throw new InvalidOperationException(string.Format("Could not resolve event name {0}", eventName));
            }

            MethodInfo[] methodInfoArray = typeof(CommandBehavior).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance);

            MethodInfo targetMethod = null;

            foreach(MethodInfo method in methodInfoArray)
            {
                object[] attributeArray = method.GetCustomAttributes(true);

                if(attributeArray.OfType<EventRaiseAttribute>().Any())
                {
                    targetMethod = method;
                    
                    break;
                }
            }

            if(targetMethod == null)
            {
                Debug.Assert(false, string.Format("invalid method type. type = {0}", eventName));
                
                return;
            }

            Delegate eventHandler = Delegate.CreateDelegate(eventInfo.EventHandlerType, null, targetMethod);

            owner.SetValue(EventHandlerProperty, eventHandler);

            eventInfo.AddEventHandler(owner, eventHandler);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 이벤트 핸들러 처리하기 - EventHandler(sender, e)

        /// <summary>
        /// 이벤트 핸들러 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        [EventRaise]
        private void EventHandler(object sender, EventArgs e)
        {
            DependencyObject d = sender as DependencyObject;

            if(d == null)
            {
                return;
            }

            ICommand command = d.GetValue(CommandProperty) as ICommand;

            if(command == null)
            {
                return;
            }

            if(command.CanExecute(null) == false)
            {
                return;
            }

            command.Execute(e);
        }

        #endregion
    }
}

 

728x90

 

▶ ReplayCommand.cs

using System;
using System.Windows.Input;

namespace TestProject
{
    /// <summary>
    /// 릴레이 명령
    /// </summary>
    public class RelayCommand : ICommand
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 실행 가능 여부 변경시 - CanExecuteChanged

        /// <summary>
        /// 실행 가능 여부 변경시
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 실행 액션
        /// </summary>
        private readonly Action<object> executeAction;

        /// <summary>
        /// 실행 가능 여부 프레디킷
        /// </summary>
        private readonly Predicate<object> canExecutePredicate;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - RelayCommand(executeAction, canExecutePredicate)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="executeAction">실행 액션</param>
        /// <param name="canExecutePredicate">실행 가능 여부 프레디킷</param>
        public RelayCommand(Action<object> executeAction, Predicate<object> canExecutePredicate)
        {
            if(executeAction == null)
            {
                throw new ArgumentNullException("executeAction");
            }

            this.executeAction       = executeAction;
            this.canExecutePredicate = canExecutePredicate;
        }

        #endregion
        #region 생성자 - RelayCommand(executeAction)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="executeAction">실행 액션</param>
        public RelayCommand(Action<object> executeAction) : this(executeAction, null)
        {
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 실행하기 - Execute(parameter)

        /// <summary>
        /// 실행하기
        /// </summary>
        /// <param name="parameter">파라미터</param>
        public void Execute(object parameter)
        {
            this.executeAction(parameter);
        }

        #endregion
        #region 실행 가능 여부 구하기 - CanExecute(parameter)

        /// <summary>
        /// 실행 가능 여부 구하기
        /// </summary>
        /// <param name="parameter">파라미터</param>
        /// <returns>실행 가능 여부</returns>
        public bool CanExecute(object parameter)
        {
            return this.canExecutePredicate == null ? true : this.canExecutePredicate(parameter);
        }

        #endregion
    }
}

 

300x250

 

▶ MainWindow.xaml

<Window x:Class="TestProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestProject"
    Width="800"
    Height="600"
    Title="커스텀 명령 동작을 사용해 이벤트 명령 실행하기"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Grid>
        <Button Name="button"
            Width="100"
            Height="30"
            Content="테스트"
            local:CommandBehavior.Event="MouseWheel" 
            local:CommandBehavior.Command="{Binding WheelCommand}" />
    </Grid>
</Window>

 

▶ MainWindow.xaml.cs

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

namespace TestProject
{
    /// <summary>
    /// 메인 윈도우
    /// </summary>
    public partial class MainWindow : Window
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// WHEEL 명령
        /// </summary>
        private RelayCommand wheelCommand;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region WHEEL 명령 - WheelCommand

        /// <summary>
        /// WHEEL 명령
        /// </summary>
        public ICommand WheelCommand
        { 
            get
            {
                return this.wheelCommand ?? (this.wheelCommand = new RelayCommand(ExecuteWheelCommand));
            }
        }

        #endregion


        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainWindow()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            DataContext = this;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region WHEEL 명령 실행하기 - ExecuteWheelCommand(parameter) 

        /// <summary>
        /// WHEEL 명령 실행하기
        /// </summary>
        /// <param name="parameter">매개 변수</param>
        private void ExecuteWheelCommand(object parameter) 
        {
            MouseWheelEventArgs e = parameter as MouseWheelEventArgs; 

            if(e == null) 
            { 
                return;
            }

            MessageBox.Show($"마우스 휠을 움직였습니다 : {e.Delta}");
        }

        #endregion
    }
}
728x90
반응형
그리드형
Posted by 사용자 icodebroker
TAG , ,

댓글을 달아 주세요