2009-10-11 6 views
20

저는 WPF에 비교적 익숙하지 않습니다. Windows Forms과 달리 WPF 컨트롤 계층 구조는 IDisposable을 지원하지 않습니다. Windows Forms에서 사용자 정의 컨트롤이 관리되는 리소스를 사용하면 모든 컨트롤이 구현 한 Dispose 메서드를 재정 의하여 리소스를 정리하는 것이 매우 쉽습니다.WPF 사용자 컨트롤의 올바른 정리

WPF에서 이야기는 그렇게 단순하지 않습니다. WPF 컨트롤에 관리되지 않는 리소스가 없기 때문에 WPF에서 IDisposable을 구현하지 않는다는 Microsoft의 첫 번째 주제는 분명합니다. 이것이 사실 일지 모르지만 WPF 클래스 계층의 사용자 확장이 관리 된 리소스를 실제로 (모델을 통해 직접 또는 간접적으로) 사용할 수 있다는 사실을 완전히 놓친 것 같습니다. IDisposable을 구현하지 않으면 Microsoft는 사용자 지정 WPF 컨트롤이나 창에서 사용하는 관리되지 않는 리소스를 정리할 수있는 유일한 보장 된 메커니즘을 효과적으로 제거했습니다.

둘째, Dispatcher.ShutdownStarted에 대한 몇 가지 참조를 발견했습니다. ShutdownStarted 이벤트를 사용하려고했지만 모든 컨트롤에 대해 실행되지 않는 것 같습니다. WPF UserControl은 ShutdownStarted에 대한 핸들러를 구현했으며, 결코 호출되지 않습니다. Windows 또는 WPF App 클래스에서만 작동하는지 확실하지 않습니다. 그러나 제대로 발사되지 않습니다 및 응용 프로그램이 닫힐 때마다 열려있는 PerformanceCounter 개체가 누출되고 있습니다.

Dispatcher.ShutdownStarted 이벤트보다 관리되지 않는 리소스를 정리하는 것이 더 좋은 대안이 있습니까? Dispose가 호출되도록 IDisposable을 구현하는 데 필요한 트릭이 있습니까? 가능하다면 은 마무리자를 사용하여을 사용하지 않는 것이 좋습니다.

답변

12

Dispatcher.ShutdownStarted가 실제로 WPF가 UserControls에서 리소스를 삭제하기 위해 제공하는 유일한 메커니즘 인 것처럼 보일 까봐 걱정됩니다. (내가 얼마 전 물었던 매우 similar question를 보라).

문제를 해결하는 또 다른 방법은 모든 가능한 일회용 리소스를 코드 뒤에서 개별 클래스 (예 : MVVM 패턴을 사용하는 경우 ViewModel)로 옮기는 것입니다. 그런 다음 상위 레벨에서 주 윈도우를 닫고 Messenger 클래스를 통해 모든 ViewModel에 알릴 수 있습니다.

Dispatcher.ShutdownStarted 이벤트가 표시되지 않습니다. 귀하의 UserControls가 당시 최상위 창에 연결되어 있습니까?

+4

+1 코드를 사용하여 일회용 리소스를 이동합니다. WPF의 핵심 학습 포인트 중 하나는 코드 바인딩을 최소화하여 데이터 바인딩 아키텍처의 장점과 표현력을 활용하는 것입니다. 배울 수있는 고통스러운 일 (학습 곡선은 절벽을 오르는 것보다 낫지 만) WPF 생각 모드를 "얻을 때"보람을 느낍니다. –

+0

모든 일회용 리소스는 실제로 IDisposable 인 ViewModel에 있습니다. Dispatcher.ShutdownStarted 이벤트가 실행되지 않는 이유에 대해 정말 혼란 스럽습니다. 성능 카운터 컨트롤 (및 관련 ViewModel)은 실제로 에 포함되어 있으므로 에 WPF 그래프에 첨부됩니다. – jrista

+1

@Greg D : 일반적으로 WPF 모델을 얻습니다. WPF의 기본 사항을 파악하자마자 MVVM을 사용하기 시작했으며 CodeBehind는 기본적으로 InitializeComponent에 대한 기본 생성자 및 호출과 같이 매우 가볍습니다. WPF의 구성 가능성과 데이터 바인딩 기능은 놀라운 것 이상의 것이므로 선택하지 않으면 Windows 양식으로 돌아 가지 않을 것입니다. – jrista

9

메커니즘은 Winforms와 다르기 때문에 IDisposable 인터페이스는 WPF에서 (거의) 의미가 없습니다. WPF에서는 비주얼하고 논리적 인 트리를 염두에 두어야합니다.
그래서 모든 시각적 객체는 일반적으로 다른 객체의 자식으로 존재합니다. WPF 구축 메커니즘의 기본은 시각적 객체를 계층 적으로 연결 한 다음 유용하지 않을 때 분리하여 파괴하는 것입니다.

UIElement 이후로 노출 된 OnVisualParentChanged 메서드를 확인할 수 있습니다.이 메서드는 시각적 개체가 연결되어 있고 언제 분리되는지를 호출합니다. 그것은 관리되지 않는 객체 (소켓, 파일 등)를 처리하기에 적합한 장소 일 수 있습니다.

+0

OnVisualParentChanged에 대한 정보 주셔서 감사합니다. 나는 그걸 가지고 놀고 내 문제를 해결하는 데 도움이되는지 확인해 보겠습니다. – jrista

0

다른 사람들이이 문제에 대한 유용한 정보를 제공했지만, IDisposable이없는 이유에 대해 많이 설명 할 수있는 정보가 조금 있습니다. 기본적으로 WPF (및 Silverlight)는 WeakReferences를 많이 사용합니다. 이렇게하면 GC가 여전히 수집 할 수있는 객체를 참조 할 수 있습니다.나도이과의 differents 옵션을 테스트 한 후보고 있었다

+0

통찰력을 주셔서 감사합니다. 피트. 좀 더 자세히 설명하는 링크가 있다면 궁금합니다. WeakReferences의 과도한 사용이 문제를 일으키지 않는지 궁금합니다. 그들은 틈새 상황에서 강력한 도구가 될 수 있지만 WPF에서 어떻게 사용되는지 상상할 수 없습니다. – jrista

5

내가 때 부모 호출 Children.Clear() 방법 및 이미 항목은 아동에 추가 한 것을 깨달았다 베네치아

protected override void OnVisualParentChanged(DependencyObject oldParent) 
    { 
     if (oldParent != null) 
     { 
      MyOwnDisposeMethod(); //Release all resources here 
     } 

     base.OnVisualParentChanged(oldParent); 
    } 

의 솔루션을 구현 DependencyObject에이 값을했다. 그러나 부모가 항목 (Children.Add(CustomControl))을 추가하고 자식이 비어 있으면 DependencyObject가 null입니다.

+0

if (Parent == null)로 변경하여 컨트롤을 다른 컨테이너로 이동하면 자체 파괴되지 않도록합니다. – Sean

관련 문제