2009-07-19 3 views
5

문제 : 개체 목록이 포함 된 문서 클래스가 있습니다. 이러한 개체는 SolutionExpired, DisplayExpired 등의 이벤트를 발생시킵니다.이 문서는 이에 응답해야합니다.한 번에 모든 이벤트 처리기 제거

문서는 개체를 교환 할 수 있지만 한 개체가 두 개 이상의 문서의 일부가되어서는 안됩니다.

내 문서 클래스에는 이벤트 처리기 역할을하는 일련의 메소드가 포함되어 있습니다. 개체가 문서에 들어갈 때마다 나는 AddHandler을 사용하여 이벤트를 설정하고 개체가 문서에서 제거 될 때마다 RemoveHandler을 사용하여 손상을 취소합니다. 그러나 모든 단계가 제대로 수행되었는지 확인하기가 어려워서 불량 이벤트 처리기로 끝날 수도 있습니다.

짧은 이야기; 특정 메서드를 가리키는 모든 처리기를 제거하려면 어떻게합니까? 참고로 잠재적 이벤트 소스 목록이 없으므로 어디서나 저장할 수 있습니다. 같은

뭔가 :

RemoveHandler *.SolutionExpired, AddressOf DefObj_SolutionExpired 
+0

가능한 복제본 [컨트롤에서 모든 이벤트 처리기를 제거하는 방법] (http://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control) – ChrisF

+0

가능 [컨트롤에서 모든 이벤트 처리기를 제거하는 방법] (https://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control) –

답변

5

Delegate.RemoveAll()을 사용할 수 있습니다.

public void Form_Load(object sender, EventArgs e) 
{ 
    button1.Click += new EventHandler(button1_Click); 
    button1.Click += new EventHandler(button1_Click); 
    button2.Click += new EventHandler(button2_Click); 
    TestEvent += new EventHandler(Form_TestEvent); 
} 
event EventHandler TestEvent; 
void OnTestEvent(EventArgs e) 
{ 
    if (TestEvent != null) 
     TestEvent(this, e); 
} 
void Form_TestEvent(object sender, EventArgs e) 
{ 
    MessageBox.Show("TestEvent fired"); 
} 
void button2_Click(object sender, EventArgs e) 
{ 
    Delegate d = TestEvent as Delegate; 
    TestEvent = Delegate.RemoveAll(d, d) as EventHandler; 
} 
void button1_Click(object sender, EventArgs e) 
{ 
    OnTestEvent(EventArgs.Empty); 
} 

당신은 당신이 그것을에 전달하는 대의원의 내용을 변경하지 않는 것을주의해야한다, 그것은 변경된 대리자를 반환 (관심있는 부분은 button2_Click에있다). 따라서 button1.Click+= 또는 -= 만 사용할 수 있으며 양식은 =이 아니므로 양식에서 삭제 한 버튼의 이벤트는 변경할 수 없습니다. 또한,

button1.Click = Delegate.RemoveAll(d, d) as EventHandler; 

을이를 구현하고 어디서나 경쟁 조건의 잠재적 위해 밖으로보고하고 있는지 확인이 컴파일되지 않습니다.다른 스레드에 의해 호출되는 이벤트에서 핸들러를 제거하는 경우 정말 이상한 행동으로 끝날 수 있습니다!

+4

개인 수준 액세스 권한이없는 이벤트에서 처리기를 제거해야하는 OP 조건을 감안할 때 이것이 어떻게 받아 들여지지는 않습니다. 나는 뭔가를 놓치고 있어야합니다! –

+1

OP의 질문은 vb.net에 관한 동안 이것은 또한 C#입니다. 두 가지가 겹치는 부분이 많지만 이벤트 구문은 이벤트 구문이 크게 다릅니다. – user81993

1
public class TheAnswer 
{ 
    public event EventHandler MyEvent = delegate { }; 

    public void RemoveFromMyEvent(string methodName) 
    { 
     foreach (var handler in MyEvent.GetInvocationList()) 
     { 
      if (handler.Method.Name == methodName) 
      { 
       MyEvent -= (EventHandler)handler; 
      } 
     } 
    } 
} 

편집 2 : 내 오해 사과 - 나는 당신이 당신의 원래의 게시물에서 이벤트 소스에 대한 액세스 권한을 가지고 있지에 대해 꽤 명확했다 것을 알 수있다.

이 문제를 해결하는 가장 간단한 방법은 개체 - 문서 바인딩의 공유 사전을 구현하는 것입니다. 개체가 문서에 들어갈 때 사전에 다른 문서에 대한 기존 바인딩이 있는지 확인하십시오. (있는 경우) 새 문서에 추가하기 전에 이전 문서를 참조하는 핸들러를 제거하십시오. 어느 쪽이든, 새 바인딩으로 사전을 업데이트하십시오.

대부분의 경우 성능과 메모리에 미치는 영향은 무시할 수 있습니다. 수만 개의 작은 개체를 다루고 문서간에 자주 교환하지 않으면 각 키/값 쌍의 메모리 오버 헤드와 성능이 저하되지 않는 한 각 조회 작업은 상당히 작아야합니다.

대안 : 문서 보낸 사람이 문서와 더 이상 관련이 없다는 것을 (문서 이벤트 처리기에서) 감지 할 수 있으면 이벤트를 거기에서 분리 할 수 ​​있습니다.

이것은 이미 거부했을지도 모르는 종류의 아이디어처럼 보입니다.

+0

Ben, 게시 해 주셔서 감사합니다. 이. 나는 그것이 나에게 (또는 그 문제에 대한 VB 컴파일러) 많은 의미를 가지지 않는 것이 아닌가 걱정된다. 원래 C#을 게시 할 수 있습니까? –

+1

원래 C# 버전을 그대로두고 있어야한다는 것을 알고있었습니다. :-) –

+0

감사합니다. Ben, 여기서하고있는 것을 보았습니다.하지만이 함수를 잘못 생각하지 않으면 이벤트를 발생시키는 인스턴스에 대한 참조가 있다고 가정합니다. 이 객체들은 지평선을 넘어 어딘가에있는 다른 목록으로 사라진 지 오래되었습니다. 핸들러를 정의하는 클래스가 아니라 이벤트를 발생시키는 클래스에 핸들러 대리자가 정의되어 있으므로이 작업을 수행 할 수 없다고 생각하기 시작했습니다. –

1

Delegate.RemoveAll을 사용합니다 (대리 인스턴스가 비공개 인 경우 리플렉션을 사용했을 수 있습니다).

+0

왜냐하면이 소스의 인스턴스가 있어야하기 때문입니다. ... 나는 더 이상 개체를 발생시키는 이벤트에 대한 액세스 권한이 없으며 처리기 만 액세스 할 수 있습니다. –