첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

728x90
반응형

TestProject.zip
다운로드

▶ DelegateCommand.cs

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;

namespace TestProject
{
    /// <summary>
    /// 대리자 명령
    /// </summary>
    public class DelegateCommand : 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 object lockObject = new object();

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

        /// <summary>
        /// 실행 가능 여부 함수
        /// </summary>
        private readonly Func<object, bool> canExecuteFunc;

        /// <summary>
        /// 실행 여부
        /// </summary>
        private bool isExecuting;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public
        
        #region 실행 여부 - IsExecuting

        /// <summary>
        /// 실행 여부
        /// </summary>
        public bool IsExecuting
        {
            get
            {
                lock(this.lockObject)
                {
                    return this.isExecuting;
                }
            }
            private set
            {
                lock(this.lockObject)
                {
                    this.isExecuting = value;
                }
            }
        }

        #endregion

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

        #region 생성자 - DelegateCommand(executeAction, canExecuteFunc)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="executeAction">실행 액션</param>
        /// <param name="canExecuteFunc">실행 가능 여부 함수</param>
        public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecuteFunc)
        {
            if(executeAction == null)
            {
                throw new ArgumentNullException(nameof(executeAction));
            }

            this.canExecuteFunc = canExecuteFunc;

            this.executeAction = parameter =>
            {
                bool canExecute = this.canExecuteFunc?.Invoke(parameter) ?? true;

                if(canExecute)
                {
                    executeAction(parameter);
                }
            };
        }

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

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

        #endregion

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

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

        /// <summary>
        /// 실행 가능 여부 구하기
        /// </summary>
        /// <param name="parameter">매개 변수</param>
        /// <returns>실행 가능 여부</returns>
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            if(IsExecuting)
            {
                return false;
            }

            return this.canExecuteFunc == null || this.canExecuteFunc(parameter);
        }

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

        /// <summary>
        /// 실행 가능 여부 구하기
        /// </summary>
        /// <returns>실행 가능 여부</returns>
        public bool CanExecute() => CanExecute(null);

        #endregion
        #region 비동기 실행하기 - ExecuteAsync(parameter)

        /// <summary>
        /// 비동기 실행하기
        /// </summary>
        /// <param name="parameter">매개 변수</param>
        /// <returns>구성 태스크 대기 가능형</returns>
        public ConfiguredTaskAwaitable ExecuteAsync(object parameter)
        {
            return Task.Run
            (
                (Func<Task>)
                (
                    async () =>
                    {
                        if(IsExecuting)
                        {
                            return;
                        }

                        try
                        {
                            IsExecuting = true;

                            await Application.Current.Dispatcher.BeginInvoke
                            (
                                this.executeAction,
                                DispatcherPriority.Normal,
                                parameter
                            );
                        }
                        catch(Exception exception)
                        {
                            Debug.WriteLine($"Could not execute command. {exception.Message}");

                            throw;
                        }
                        finally
                        {
                            IsExecuting = false;

                            CommandManager.InvalidateRequerySuggested();
                        }
                    }
                )
            ).ConfigureAwait(true);
        }

        #endregion
        #region 비동기 실행하기 - ExecuteAsync()

        /// <summary>
        /// 비동기 실행하기
        /// </summary>
        /// <returns>구성 태스크 대기 가능형</returns>
        public ConfiguredTaskAwaitable ExecuteAsync() => ExecuteAsync(null);

        #endregion
        #region 실행하기 - Execute(parameter)

        /// <summary>
        /// 실행하기
        /// </summary>
        /// <param name="parameter">매개 변수</param>
        public void Execute(object parameter) => ExecuteAsync(parameter);

        #endregion
        #region 실행하기 - Execute()

        /// <summary>
        /// 실행하기
        /// </summary>
        public void Execute() => ExecuteAsync(null);

        #endregion
    }
}

 

▶ 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"
    Width="800"
    Height="600"
    Title="ICommand 인터페이스 : 대리자 명령 사용하기"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Grid>
        <StackPanel
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
            <Button
                HorizontalAlignment="Center"
                Margin="10"
                Width="100"
                Height="30"
                Command="{Binding RunCommand}"
                Content="테스트" />
            <ListBox Name="listBox"
                HorizontalAlignment="Center"
                Margin="10"
                Width="300"
                Height="300" />
        </StackPanel>
    </Grid>
</Window>

 

▶ MainWindow.xaml.cs

using System;
using System.Windows;
using System.Threading.Tasks;

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

        #region Field

        /// <summary>
        /// 실행 명령
        /// </summary>
        private DelegateCommand runCommand;

        #endregion

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

        #region 실행 명령 - RunCommand

        /// <summary>
        /// 실행 명령
        /// </summary>
        public DelegateCommand RunCommand => this.runCommand ??
        (
            this.runCommand = new DelegateCommand
            (
                async parameter =>
                {
                    this.listBox.Items.Add($"[{DateTime.Now.ToString("HH:mm:ss")}] 버튼을 클릭했습니다.");

                    await Task.Delay(3000);

                    this.listBox.Items.Add($"[{DateTime.Now.ToString("HH:mm:ss")}] 작업을 실행했습니다.");
                }
            )
        );

        #endregion

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

        #region 생성자 - MainWindow()

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

            DataContext = this;
        }

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

댓글을 달아 주세요