2Bbear's knowledge workshop

정보 참고는 

https://illef.tistory.com/entry/WPF-Command-Part4-DelegateCommand

http://www.sysnet.pe.kr/2/0/10917

이곳에서 했습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
 
namespace HowToDelegateCommand
{
    class DelegateCommand<T> : ICommand
    {
        Action<T> executeTargets = delegate { };
        Func<bool> canExecuteTargets = delegate { return false; };
        bool m_Enabled = false;
 
        public bool CanExecute(object parameter)
        {
            Delegate[] targets = canExecuteTargets.GetInvocationList();
            foreach(Func<bool> target in targets)
            {
                m_Enabled = false;
                bool localenable = target.Invoke();
                if(localenable)
                {
                    m_Enabled = true;
                    break;
                }
            }
            return m_Enabled;
        }
        public void Execute(object parameter)
        {
            if (CanExecute(parameter))
            {
                executeTargets(parameter !=null?(T)parameter: default(T));
            }
        }
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
        public event Action<T> ExecuteTargets
        {
            add
            {
                executeTargets += value;
            }
            remove
            {
                executeTargets -= value;
            }
        }
        public event Func<bool> CanExecuteTargets
        {
            add
            {
                canExecuteTargets += value;
            }
            remove
            {
                canExecuteTargets -= value;
            }
        }
        
       
 
       
    }
}
 
cs



Generic을 이용한 Command 구현입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#region 어셈블리 System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.dll
#endregion
 
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Markup;
 
namespace System.Windows.Input
{
    //
    // 요약:
    //     명령을 정의합니다.
    [TypeConverter("System.Windows.Input.CommandConverter, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null")]
    [TypeForwardedFrom("PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
    [ValueSerializer("System.Windows.Input.CommandValueSerializer, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null")]
    public interface ICommand
    {
        //
        // 요약:
        //     명령을 실행해야 하는지 여부에 영향을 주는 변경이 발생할 때 발생합니다.
        event EventHandler CanExecuteChanged;
 
        //
        // 요약:
        //     명령을 현재 상태에서 실행할 수 있는지를 결정하는 메서드를 정의합니다.
        //
        // 매개 변수:
        //   parameter:
        //     명령에 사용된 데이터입니다. 명령에서 데이터를 전달할 필요가 없으면 이 개체를 null로 설정할 수 있습니다.
        //
        // 반환 값:
        //     이 명령을 실행할 수 있으면 true이고, 그러지 않으면 false입니다.
        bool CanExecute(object parameter);
        //
        // 요약:
        //     명령이 호출될 때 호출될 메서드를 정의합니다.
        //
        // 매개 변수:
        //   parameter:
        //     명령에 사용된 데이터입니다. 명령에서 데이터를 전달할 필요가 없으면 이 개체를 null로 설정할 수 있습니다.
        void Execute(object parameter);
    }
}
cs


위 코드에서 사용한 ICommand는 이렇게 구성이 되어 있습니다.


CanExecute의 경우 실행이 가능하다면 return을 하는 형식으로 구현 할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class RelayCommand : ICommand
{
    public event EventHandler CanExecuteChanged;
 
    public bool CanExecute(object parameter)
    {
        return DateTime.Now.Hour != 9;
    }
 
    public void Execute(object parameter)
    {
        Console.WriteLine(DateTime.Now + ": RelayCommand.Execute - " + parameter);
    }
}

cs


이렇게 말입니다.

위 코드는 현재 시간이 9시가 아닐 경우 return을 하는 형태입니다.

즉 9시가 아닌 경우에만 동작을 하도록 하고 싶을 경우 이렇게 작성하게 됩니다.


1
2
3
4
if (Command.CanExecute(null== true)
            {
                Command.Execute(txt);
            }
cs

그리고 위 커맨드를 다른 곳에서 호출 할때 이런 식으로 호출하게 됩니다.

즉 CanExecute가 반환된 값이 있을때 Command.Excute를 한다고 말이죠.


=====================================================================

그러한 맥락으로 보았을 때 DelegateCommand는

어디선가 호출자가 Command를 호출할때, 즉 어떤 호출자가 CanCommand를 실행하였을 때,

해당 호출자가 CanCommand가 갖고 있는 Target들, 즉 호출을 할 수 있는 호출자 목록 안에 있을 때 해당 호출자에 맞추어 Execute를 실행하게 해주는 코드를 갖고있습니다.


따라서 CanCommand 에는 foreach 문으로 자신에게 할당 되어 있는 호출자들을 매번 검색해야합니다.


순서는 execute -> CanExecute의 순으로서. CanExecute에서 "이 호출자는 실행해도 되는 호출자야"라고 허락을 해야 execute가 실행하게 되는 구조입니다.