2011-01-06 2 views
2

커맨드 동작으로 사용자 정의 컨트롤을 만드는 중이며 이상한 점이있었습니다. 내가 찾은 일부 기사는 CanExecuteChangedHandler EventHandler를 정적으로 선언하고 다른 항목은 정적이 아닌 것으로 선언했습니다. Microsoft의 SDK 설명서는 정적이지만 정적으로 선언하면 여러 컨트롤을 사용할 때 이상한 동작을 보입니다.WPF 컨트롤에서 EventHandler를 정적 또는 비 정적으로 선언하십시오.

private static EventHandler canExecuteChangedHandler; 

private void AddSecureCommand(ISecureCommand secureCommand) 
{ 
    canExecuteChangedHandler = new EventHandler(CanExecuteChanged); 
    securityTypeChangedHandler = new EventHandler(SecurityTypeChanged); 

    if (secureCommand != null) 
    { 
     secureCommand.CanExecuteChanged += canExecuteChangedHandler; 
     secureCommand.SecurityTypeChanged += securityTypeChangedHandler; 
    } 
} 

누군가 적절한 방법을 알고 있습니까? 정적 EventHandler가 작동하지 않게하는 잘못된 작업을하고 있습니까?

답변

1

EventHandler의 로컬 복사본을 유지해야하는 이유는 WPF 명령 하위 시스템이 내부적으로 약한 참조를 사용하므로 CanExecuteChanged 이벤트에 추가 된 특정 대리인 개체에 대한 참조를 유지해야하기 때문입니다. 사실, 명령하는 하위 시스템 이벤트에 언제든지 추가 할 때마다 SecurityTypeChanged처럼이 연습을 준수해야합니다.

귀하의 질문에 짧은 대답은 canExecuteChangedHandler 정적이 될 수 있지만, 한 번를 초기화 만 에주의해야한다는 것입니다. 정적 인 이유는 CanExecuteChanged이 정적 인 경우 모두 new EventHandler(CanExecuteChanged)이 동일한 작업을 수행한다는 것입니다. 한 번 초기화하는 이유는 인스턴스가 다르다는 것입니다.

읽기 전용 의미 IS 바로이있는 개인 재산 : CanExecuteChanged 정적 인 경우

static EventHandler canExecuteChangedHandler 
{ 
    get 
    { 
     if (internalCanExecuteChangedHandler == null) 
      internalCanExecuteChangedHandler = new EventHandler(CanExecuteChanged); 
     return internalCanExecuteChangedHandler; 
    } 

} 
static EventHandler internalCanExecuteChangedHandler; 

만이 유일한 작품. 그렇지 않으면 static 한정자를 제거하십시오. 어느 경우 든 실제로 속성을 사용하도록 조심해야합니다.

이 특정 예에서는 AddSecureCommand이 처음으로 canExecuteChangedHandler이라고 불리는 두 번째 시간이 가비지 수집 될 위험이 있습니다.

마침내이 모든 것이 검은 마법처럼 들린다면, 무슨 일이 일어나고 있는지 보여주는 코드 예제가 있습니다.

container1: False 
container2: True 

가리 제 2 용기는 EventHandler "그 밑으로"가베지 수집 된 한 가비지 컬렉션시 :

public class Container 
{ 
    private WeakReference reference; 
    public object Object 
    { 
     get { return reference.IsAlive ? reference.Target : null; } 
     set { reference = new WeakReference(value); } 
    } 
} 

public class DelegateTest 
{ 
    private EventHandler eventHandler; 
    private Container container1; 
    private Container container2; 

    void MyEventHandler(object sender, EventArgs args) 
    { 
    } 

    public DelegateTest() 
    { 
     this.eventHandler = new EventHandler(MyEventHandler); 
     this.container1 = new Container { Object = this.eventHandler }; 
     this.container2 = new Container { Object = new EventHandler(MyEventHandler) }; 
     GC.Collect(); 
     Console.WriteLine("container1: {0}", this.container1.Object == null); 
     Console.WriteLine("container2: {0}", this.container2.Object == null); 
    } 
} 

이것은이 출력을 생성한다. 이것은 의도적으로 약한 참조가 작동하는 방식이며 사용자를위한 설명은 직접 참조를 유지해야합니다.

+0

가비지 수집 이유를 이해하고 있으며 클래스 수준에서 선언 된 EventHandler가 있어야한다는 것을 알고 있습니다. 내가 가지고있는 문제는 정적 인 경우 클래스를 여러 번 인스턴스화 할 때 이상한 행동을 보일 때입니다. – Brady

+0

줄 바꿈을 추가하고 주석을 달았습니다. 나는 위의 코멘트를 편집하려고했지만 분명히 나는 ​​단지 그것을 업데이트하기 위해 5 분을 얻는다. 위에서 정교하게 ... 내가 가지고있는 문제는 클래스 (또는 컨트롤)를 여러 번 인스턴스화 할 때 정적 일 때 이상한 행동을 보일 때입니다. 좀 더 연구를 한 후에 EventHandler 대리자의 타겟이 인스턴스에 특정하다는 것을 알 수 있습니다. 내 경우에는 정적 EventHandler를 사용하여 문제가 발생합니다. 정적 EventHandler를 사용할 수있는 경우가있을 수 있지만 내 경우에는 작동하지 않을 것입니다. – Brady

+0

요점을 요약하면 : 이벤트 핸들러 참조는 정적 인 경우에만 정적 일 수 있습니다. 명령 이벤트에 추가 한 후에도 수정하지 않도록 조심해야합니다.나는 대답을 업데이트 할 것이다. –

관련 문제