WPF 사용자 컨트롤 삭제


119

타사에서 사용할 사용자 지정 WPF 사용자 정의 컨트롤을 만들었습니다. 내 컨트롤에는 일회용 인 개인 멤버가 있으며 포함하는 창 / 응용 프로그램이 닫히면 dispose 메서드가 항상 호출되도록하고 싶습니다. 그러나 UserControl은 일회용이 아닙니다. IDisposable 인터페이스를 구현하고 Unloaded 이벤트를 구독하려고 시도했지만 호스트 응용 프로그램이 닫힐 때 호출되지 않았습니다. 가능하다면 특정 Dispose 메서드 호출을 기억하는 내 컨트롤의 소비자에게 의존하고 싶지 않습니다.

 public partial class MyWpfControl : UserControl
 {
     SomeDisposableObject x;

     // where does this code go?
     void Somewhere() 
     {
         if (x != null)
         {
             x.Dispose();
             x = null;
         }

     }
 }

지금까지 찾은 유일한 해결책은 Dispatcher의 ShutdownStarted 이벤트를 구독하는 것입니다. 이것이 합리적인 접근입니까?

this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;

사용자 제어의 Unloaded 이벤트는 어떻습니까?
akjoshi

2
@akjoshi : MSDN은 다음과 같이 말합니다. Unloaded 이벤트가 전혀 발생하지 않을 수 있습니다. 또한 사용자가 테마를 변경할 때 두 번 이상 트리거 될 수도 있습니다.
Dudu 2011 년

사용자 정의 컨트롤에서 IDisposable 인터페이스를 구현할 수 있지만 타사에서 Dispose 패턴 구현의 dispose 메서드를 호출 할 것이라는 보장은 없습니다. 네이티브 리소스 (예 : 파일 스트림)를 보유하고있는 경우 종료 자 사용을 고려해야합니다.
Philippe

답변:


57

여기에 흥미로운 블로그 게시물 :

http://geekswithblogs.net/cskardon/archive/2008/06/23/dispose-of-a-wpf-usercontrol-ish.aspx

Dispatcher.ShutdownStarted 에 대한 구독을 언급 하여 리소스를 폐기합니다.


1
이보다 더 깨끗한 방법이 있기를 바랐지만 지금은 이것이 최선의 방법 인 것 같습니다.
Mark Heath

35
하지만 앱이 죽기 전에 UserControl이 죽으면 어떨까요? Dispatcher는 앱이 작동 할 때만 꺼집니다. 그렇죠?
Robert Jeppesen

15
많은 컨트롤이 COM 구성 요소 또는 기타 관리되지 않는 리소스를 재사용하기 때문에 뷰로 코딩되지 않은 상태에서 무기한 유지되거나 스레드 풀 스레드에서 완료되고 결정적 할당 해제가 필요합니다.
Neutrino

1
Windows 스토어 앱에는 ShutdownStarted가 존재하지 않습니다.
Cœur

7
또는 이벤트 처리기를 역 참조하거나 해당 컨트롤에서 시작된 스레드를 중지해야합니다.
DanW

40

Dispatcher.ShutdownStarted이벤트는 응용 프로그램이 끝날 때만 발생합니다. 제어가 사용되지 않을 때 폐기 로직을 ​​호출하는 것이 좋습니다. 특히 애플리케이션 런타임 중에 제어가 여러 번 사용될 때 리소스를 해제합니다. 따라서 ioWint 의 솔루션이 바람직합니다. 코드는 다음과 같습니다.

public MyWpfControl()
{
     InitializeComponent();
     Loaded += (s, e) => { // only at this point the control is ready
         Window.GetWindow(this) // get the parent window
               .Closing += (s1, e1) => Somewhere(); //disposing logic here
     };
}

Windows 스토어 앱에는 GetWindow ()가 없습니다.
Cœur 2013

브라보, 최고의 대답.
Nic

8
쾨르은 : 윈도우 스토어 앱에서는 WPF를 사용하지 않는
앨런 Baljeu

3
더 많은 창이 있고 메인 창이 닫히지 않으면 어떻게 될까요? 또는 컨트롤이 여러 번로드 / 언로드되는 페이지에서 호스팅됩니까? 참조 : stackoverflow.com/a/14074116/1345207
L. Trabacchin

1
창이 자주 닫히지 않을 수 있습니다. 컨트롤이 목록 항목의 일부인 경우 부모 창이 닫힐 때까지 많은 항목이 생성 / 파괴됩니다.
LOST

15

소멸자를 사용하는 데주의해야합니다. 이것은 GC Finalizer 스레드에서 호출됩니다. 경우에 따라 해제 된 리소스가 생성 된 스레드와 다른 스레드에서 해제되는 것을 좋아하지 않을 수 있습니다.


1
이 경고에 감사드립니다. 이것은 정확히 내 경우였습니다! 응용 프로그램 : devenv.exe Framework 버전 : v4.0.30319 설명 : 처리되지 않은 예외로 인해 프로세스가 종료되었습니다. 예외 정보 : System.InvalidOperationException 스택 : MyControl.Finalize ()에서 내 솔루션은 코드를 종료 자에서 ShutdownStarted로 이동하는 것이 었습니다
itsho

10

다음 상호 작용 동작을 사용하여 WPF UserControls에 언로드 이벤트를 제공합니다. UserControls XAML에 동작을 포함 할 수 있습니다. 따라서 모든 단일 UserControl에 로직을 배치하지 않고도 기능을 사용할 수 있습니다.

XAML 선언 :

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

<i:Interaction.Behaviors>
    <behaviors:UserControlSupportsUnloadingEventBehavior UserControlClosing="UserControlClosingHandler" />
</i:Interaction.Behaviors>

CodeBehind 핸들러 :

private void UserControlClosingHandler(object sender, EventArgs e)
{
    // to unloading stuff here
}

행동 코드 :

/// <summary>
/// This behavior raises an event when the containing window of a <see cref="UserControl"/> is closing.
/// </summary>
public class UserControlSupportsUnloadingEventBehavior : System.Windows.Interactivity.Behavior<UserControl>
{
    protected override void OnAttached()
    {
        AssociatedObject.Loaded += UserControlLoadedHandler;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Loaded -= UserControlLoadedHandler;
        var window = Window.GetWindow(AssociatedObject);
        if (window != null)
            window.Closing -= WindowClosingHandler;
    }

    /// <summary>
    /// Registers to the containing windows Closing event when the UserControl is loaded.
    /// </summary>
    private void UserControlLoadedHandler(object sender, RoutedEventArgs e)
    {
        var window = Window.GetWindow(AssociatedObject);
        if (window == null)
            throw new Exception(
                "The UserControl {0} is not contained within a Window. The UserControlSupportsUnloadingEventBehavior cannot be used."
                    .FormatWith(AssociatedObject.GetType().Name));

        window.Closing += WindowClosingHandler;
    }

    /// <summary>
    /// The containing window is closing, raise the UserControlClosing event.
    /// </summary>
    private void WindowClosingHandler(object sender, CancelEventArgs e)
    {
        OnUserControlClosing();
    }

    /// <summary>
    /// This event will be raised when the containing window of the associated <see cref="UserControl"/> is closing.
    /// </summary>
    public event EventHandler UserControlClosing;

    protected virtual void OnUserControlClosing()
    {
        var handler = UserControlClosing;
        if (handler != null) 
            handler(this, EventArgs.Empty);
    }
}

5
여기 깃발을 올릴 것 ... 무엇 창 폐쇄를 취소하는 경우 (컨트롤이 너무 후 어쩌면 가입 무엇을 e.Cancel그것은 당신에 도달하면 여전히 거짓 WindowClosingHandler대표)? 컨트롤이 "언로드"되고 창이 계속 열립니다. 나는 확실히 Closed이벤트가 아닌 이벤트에서 이것을 할 것 Closing입니다.
Jcl 2014

6

내 시나리오는 약간 다르지만 의도는 동일합니다. 내 사용자 컨트롤을 호스팅하는 부모 창이 닫히거나 닫히는시기를 알고 싶습니다.보기 (예 : 내 usercontrol)는 일부 기능을 실행하고 정리를 수행하기 위해 closeView에서 발표자를 호출해야합니다. (우리는 WPF PRISM 애플리케이션에서 MVP 패턴을 구현하고 있습니다).

방금 usercontrol의 Loaded 이벤트에서 ParentWindowClosing 메서드를 Parent windows Closing 이벤트에 연결할 수 있다고 생각했습니다. 이렇게하면 내 Usercontrol이 부모 창이 닫힐 때를 인식하고 그에 따라 행동 할 수 있습니다!


0

언로드는 모두라고 생각하지만 4.7에는 하드가 존재합니다. 그러나 이전 버전의 .Net을 가지고 노는 경우로드 방법에서 다음을 수행하십시오.

e.Handled = true;

로드가 처리 될 때까지 이전 버전이 언로드되지 않을 것이라고 생각합니다. 다른 사람들이 여전히이 질문을하고 있고 이것이 해결책으로 제안 된 것을 보지 못했기 때문에 게시했습니다. 나는 .Net을 일년에 몇 번만 만졌고 몇 년 전에 이것을 만났습니다. 하지만로드가 끝날 때까지 언로드가 호출되지 않는 것만 큼 간단한 지 궁금합니다. 그것이 나를 위해 작동하는 것처럼 보이지만, 다시 새로운 .Net에서는 로딩이 처리됨으로 표시되지 않더라도 항상 언로드를 호출하는 것 같습니다.


-3

UserControl에는 소멸자가 있습니다. 왜 그것을 사용하지 않습니까?

~MyWpfControl()
    {
        // Dispose of any Disposable items here
    }

이것은 작동하지 않는 것 같습니다. 나는 그 접근 방식을 시도했지만 결코 호출되지 않았습니다.
JasonD 2010 년

9
소멸자가 아니라 종료 자입니다. 항상 종료자를 구현하고 쌍으로 처리하지 않으면 누출 위험이 있습니다.
Mike Post

1
그리고 종료 자에서는 관리되지 않는 개체 만 정리해야하고 관리되는 개체는 정리하지 않아야합니다. 종료자는 GC 스레드에서 지정되지 않은 순서로 실행되므로 관리되는 개체가 더 일찍 마무리되고 Dispose ()에 스레드 선호도가있을 수 있기 때문입니다.
Dudu 2011 년

2
joeduffyblog.com/2005/04/08/… 내가 찾은 Finalize 및 Dispose에 대한 가장 좋은 설명입니다. 읽을만한 가치가 있습니다.
dss539 2014
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.