2011-04-28 7 views
6

PRISM 및 MVVM을 사용하여 WPF를 사용하기 시작합니다. 내가 직면 한 한가지 문제는 이전에 ViewModel에 가입 한 EventAggregator 이벤트를 구독 취소하기에 좋은 장소/모범 사례를 찾을 수 없다는 것입니다. 소멸자에서 탈퇴를 호출하는 다음 해결책은 너무 늦습니다. 다음 가비지 콜렉션으로 실행 중입니다.ViewModels의 이벤트 애널리스트 이벤트 수신 거부

public class ViewModel : ViewModelBase 
{ 
    public ViewModel() 
    { 
     var eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>(); 
     eventAggregator.GetEvent<SeriesSelectionChangedEvent>().Subscribe(OnSeriesSelectionChanged); 
    } 

    ~ViewModel() 
    { 
     var eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>(); 
     eventAggregator.GetEvent<SeriesSelectionChangedEvent>().Unsubscribe(OnSeriesSelectionChanged); 
    } 

    void OnSeriesSelectionChanged(SeriesSelectionChangedEventArgs e) 
    { 
    } 
} 

답변

3

여러분에게 달려 있습니다! 애플리케이션이 더 이상 필요하지 않을 때 ViewModel에 알릴 수 있다면 거기에서 구독을 취소해야합니다.

예를 들어, 우리 프로젝트에는 IViewDisposeService가 있습니다. 뷰 (또는 모델)가 결정 론적 파이널 라이즈를 필요로하는 경우, IViewDisposeService에 나타납니다. 그런 다음 Core는 동일한 서비스를 사용하여 등록 된보기가 영역에서 제거되었을 때 알림을 보냅니다.

또 다른 방법은 명령을 사용하는 것입니다. 뷰를 닫을 때 호출해야하는 모델 노출 명령. ViewModel은 명령 처리기를 사용하여 가입을 취소 할 수 있습니다.

그런데 EventAggregator가 ViewModel을 유지할 것이라고 걱정하면 Prism의 EventAggregator가 약한 참조를 사용하기 때문에 문제가되지 않습니다.

+2

이벤트 등록 중에 강력한 참조를 선택할 수도 있습니다. –

+0

그것은 내게 달렸습니다. 그것이 내가 의심했던 것입니다. 내 생각에 두 번째 제안 - 시야를 통한 명령 실행 -이 내 필요에 부합한다고 생각합니다. 좋은 대답! –

+0

@Daniel : 죄송합니다. 그것은 오래 전, 내 프로젝트에서 마지막 이벤트를 추가했을 때였습니다 :)) –

3

언젠가는 나도 같은 문제에 직면했다. 여기에 우리가 한 일이 있습니다 (WPF App). UserControl을,는 IDisposable : DisposableUserControl -

  1. 는 새로운 기본 클래스를 생성합니다. 여기에는 사용자 정의 컨트롤을 배치하는 논리가 포함됩니다. 코드가 결국 추가되었습니다.
  2. 응용 프로그램의 모든 사용자 정의 컨트롤을 DisposableUserControl로 바꿉니다. 예 : < 앱 : DisposableUserControl ....> </app.DisposableUserControl>
  3. VM의 Dispose() 메소드에서 호출되는 ViewModelBase의 OnDispose 메소드 (가상)를 추가합니다. 앱의 ViewModel에서이 OnDispose 메소드를 당신은 당신의 이벤트를 구독 취소 할 것입니다. 뭔가가 ~
    OnDispose() {base.Dispose(); 구독 취소 이벤트 (abcEventSubscribername); }

코드

/// <summary> 
    /// Falg used to avoid calling dispose multiple times on same user control 
    /// </summary> 
    private bool isDisposed; 



    /// <summary> 
    /// Dispose 
    /// </summary> 
    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this);   
    } 

    /// <summary> 
    /// If disposing equals true, the method has been called directly 
    /// or indirectly by a user's code. Managed and unmanaged resources 
    /// can be disposed. If disposing equals false, the method has been called by the 
    /// runtime from inside the finalizer and you should not reference 
    /// other objects, only unmanaged resources can be disposed. 
    /// </summary> 
    /// <param name="disposing"></param> 
    protected virtual void Dispose(bool disposing) 
    { 
     if (!this.isDisposed) 
     { 
      this.isDisposed = true; 
      if (disposing) 
      { 
       UtilityFunctions.DisposeChildDisposableUserControls(this); 

       if (this.DataContext != null && this.DataContext is IDisposable) 
       { 
        var parent = LogicalTreeHelper.GetParent(this); 

        if (parent == null || ((parent as FrameworkElement).DataContext != this.DataContext)) 
        { 
         (this.DataContext as IDisposable).Dispose(); 
        } 
        BindingOperations.ClearAllBindings(this); 
        this.DataContext = null; 
       } 
      } 
     } 
    } 
2

이 언로드 될 때 당신은보기는 뷰 모델에 통보 할 수 (또는 윈도우의 경우 그것은 닫혀있을 때). 그런 다음 ViewModel의 Unloaded/Closed 핸들러에서 탈퇴 할 수 있습니다. 그게 내가 응용 프로그램에서하는 방법입니다.

+0

이것은 본질적으로 Marat 's와 비슷한 제안입니다. 나는 그 길로 갈 것 같아. –

+0

저는 Cinch v2를 MVVM 프레임 워크로 사용합니다. 로드/언로드에 대한 이벤트를 자동으로 추가합니다. –

관련 문제