실전 취소 가능한 버튼 컨트롤 만들기
 
Umc.Core.EventHandlerDictionary 클래스
이 클래스는 Umc.Core 프로젝트에 포함된 클래스 입니다. 이 클래스의 이름에서 알 수 있듯이 이벤트를 사전(Dictionary)로 관리하도록 하기 위한 클래스 입니다.
 
namespace Umc.Core
{
        ///<summary>
        /// Umc.Core<br/>
        /// Delegate 담는 EventHandlerDictionary 컬렉션
        ///</summary>
        public class EventHandlerDictionary : IDisposable
        {
               ///<summary>
               /// Umc.Core<br/>
               /// Event 담는컬렉션
               ///</summary>
               private Dictionary<object,Delegate> eventDictionary = new Dictionary<object,Delegate>();
 
               ///<summary>
               /// Umc.Core<br/>
               /// EventHandlerDictionary EventHandler 추가한다.
               ///</summary>
               ///<param name="key">키값</param>
               ///<param name="value">Delegate</param>
               public void AddHandler(object key, Delegate value)
               {
                       if ( eventDictionary.ContainsKey(key) )
                       {
                              eventDictionary[key] = Delegate.Combine(eventDictionary[key], value);
                       }
                       else
                       {
                              eventDictionary[key] = value;
                       }
               }
 
               ///<summary>
               /// Umc.Core<br/>
               /// EventHandlerDictionary EventHandler 제거한다.
               ///</summary>
               ///<param name="key">키값</param>
               ///<param name="value">Delegate</param>
               public void RemoveHandler(object key, Delegate value)
               {
                       if ( eventDictionary.ContainsKey(key) )
                       {
                              eventDictionary[key] = Delegate.Remove(eventDictionary[key], value);
                       }
               }
 
               public bool Contains(object key)
               {
                       return this.eventDictionary.ContainsKey(key);
               }
 
               ///<summary>
               /// Umc.Core<br/>
               /// EventHandlerDictionary 인덱서
               ///</summary>
               ///<param name="key"></param>
               ///<returns></returns>
               public Delegate this[object key]
               {
                       get { return eventDictionary[key]; }
                       set { eventDictionary[key] = value; }
               }
 
               #region IDisposable 멤버
               ///<summary>
               /// Umc.Core<br/>
                /// EventHandlerDictionary 자원을해제한다.
               ///</summary>
               public void Dispose()
               {
                       if( eventDictionary != null )
                              eventDictionary.Clear();
 
                       eventDictionary = null;
               }
               #endregion
        }
}
 
클래스 내부에는 Dictionary 제네릭 클래스의 오브젝트를 생성하여, AddHandler(), RemoveHandler() 를 통해 이벤트를 사전에 추가/삭제 하는 로직이 들어있습니다.
 
 
ButtonEx 네임스페이스
Click 이벤트 전/후에 발생할 이벤트의 인자를 전달한 EventArgs 클래스 입니다. 이미 지난 회차를 보신 분이라면 그렇게 생소하지 않을 것입니다.
///<summary>
/// Before 이벤트가발생할전달될이벤트인자클래스입니다.
///</summary>
public class BeforeClickEventArgs : CancelEventArgs
{
        public string Reason { get; set; }
}
 
///<summary>
/// After 이벤트가발생할전달될이벤트인자클래스입니다.
///</summary>
public class AfterClickEventArgs : EventArgs { }
 
또한, 직관적인 코딩을 위해 Before/After 이벤트를 위한 델리게이트를 선언하였습니다. 특별한 변경된 EventArgs 와 같은 인자가 없다면 기존 EventHandler 를 활용해도 되지만, 언제든 추후에 확장될 가능성은 충분하다고 생각합니다. 그렇기 때문에 델리게이트를 선언해 주었답니다.
///<summary>
/// BeforeClick 이벤트를캡슐화하는델리게이트입니다.
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
public delegate void BeforeClickEventHandler(object sender, BeforeClickEventArgs e);
///<summary>
/// AfterClick 이벤트를캡슐화하는델리게이트입니다.
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
public delegate void AfterClickEventHandler(object sender, AfterClickEventArgs e);
 
여기서 이벤트는 사전(Dictionary) 을 통해 이벤트를 관리하게 됩니다. Umc.Core 프로젝트에 사용되는 EventHandlerDictionary 클래스의 일부를 직접 예제 클래스에 포함한 것입니다. 이 EventHandlerDictionary 에 접근하기 위한 Events 프로퍼티를 선언하였습니다.
private EventHandlerDictionary events;
///<summary>
/// EventHandlerDictionary 통해이벤트를관리합니다.
///</summary>
protected EventHandlerDictionary Events
{
        get
        {
               if( events == null )
                       events = new EventHandlerDictionary();
 
               return events;
        }
}
 
여기에서 선언된 이벤트는 EventHandlerDictionary 클래스에서 관리하게 될 것이기 때문에, event 선언에 대해 커스트마이징(?)이 필요합니다. 즉, 이벤트의 추가/삭제에 대한 액션을 변경할 필요가 있습니다.
private object EVENT_BEFORE_CLICK     = new object(); // BeforeClick 이벤트오브젝트
private object EVENT_AFTER_CLICK      = new object(); // AfterClick 이벤트오브젝트
 
///<summary>
/// BeforeClick 이벤트입니다. Click 이벤트가발생하기전에발생합니다.
///</summary>
[Description("Click 이벤트가발생하기전에발생합니다")]
public event BeforeClickEventHandler BeforeClick
{
        add
        {
               this.Events.AddHandler(EVENT_BEFORE_CLICK, value);
        }
        remove
        {
               this.Events.RemoveHandler(EVENT_BEFORE_CLICK, value);
        }
}
 
///<summary>
/// AfterClick 이벤트입니다. Click 이벤트가발생한발생합니다.
///</summary>
[Description("Click 이벤트가발생후에발생합니다")]
public event AfterClickEventHandler AfterClick
{
        add
        {
               this.Events.AddHandler(EVENT_AFTER_CLICK, value);
        }
        remove
        {
               this.Events.RemoveHandler(EVENT_AFTER_CLICK, value);
        }
}
 
여기는 각각의 Before/After 이벤트를 발생하는 메서드와 CancelEventArgs 의 Cancel 프로퍼티를 검사하는 메서드가 존재합니다. OnEventsFire() 메서드를 눈여겨 보시면 될 것 같습니다.
///<summary>
/// BeforeClick 이벤트를발생합니다.
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
protected virtual void OnBeforeClick(object sender, BeforeClickEventArgs e)
{
        if( !this.Events.Contains( EVENT_BEFORE_CLICK ) ) return;
 
        BeforeClickEventHandler handler       =
this.Events[ EVENT_BEFORE_CLICK ] as BeforeClickEventHandler;
        if( handler != null )
               handler(sender, e);
}
 
///<summary>
/// AfterClick 이벤트를발생합니다.
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
protected virtual void OnAfterClick(object sender, AfterClickEventArgs e)
{
        if( !this.Events.Contains(EVENT_AFTER_CLICK) ) return;
 
        AfterClickEventHandler handler =
this.Events[ EVENT_AFTER_CLICK ] as AfterClickEventHandler;
        if( handler != null )
               handler(sender, e);
}
 
///<summary>
/// Click 이벤트가발생할경우 BeforeClick/AfterClick 이벤트를발생합니다.
///</summary>
///<param name="sender"></param>
protected virtual void OnEventsFire( object sender )
{
        BeforeClickEventArgs beforeArgs       = new BeforeClickEventArgs();
        OnBeforeClick( sender, beforeArgs );
 
        if( beforeArgs.Cancel ) return;
 
        AfterClickEventArgs afterArgs = new AfterClickEventArgs();
        OnAfterClick( sender, afterArgs );
}
 
[Obsolete("ButtonEx 컨트롤에서는 Click 이벤트를사용하지않도록합니다. 대신 AfterClick 이벤트를사용하세요")]
protected override void OnInit(EventArgs e)
{
        base.OnInit(e);
        this.Click += new EventHandler(ServerControl1_Click);
}
 
private void ServerControl1_Click(object sender, EventArgs e)
{
        OnEventsFire(sender);
}
 
이제 간략한 소스 코드 설명은 끝났네요. 힘들게 만든 ButtonEx 서버 컨트롤을 어떻게 활용하면 될지 다음 회차를 참고하세요.
저작자 표시 비영리 동일 조건 변경 허락
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by POWERUMC 엄준일(땡초)
TAG ,