2017-12-12 9 views
-1

MVVM을 사용하여 여러보기간에 전환하는 응용 프로그램을 만듭니다. 보기는이 같은 ContentControl를 통해 인스턴스화 :내 일정에서 일정을 탈퇴해야하는 시점을 어떻게 알 수 있습니까?

기본 뷰 모델이 같은 모습
<ContentControl Name="DynamicViewControl" Content="{Binding }"> 
    <ContentControl.Resources> 
     <DataTemplate x:Key="PageOneTemplate"> 
      <pages:PageOne DataContext="{Binding PageOneViewModel}"/> 
     </DataTemplate> 
     <DataTemplate x:Key="PageTwoTemplate"> 
      <pages:PageTwo DataContext="{Binding PageTwoViewModel}"/> 
     </DataTemplate> 
     <!-- And so on... --> 
    </ContentControl.Resources> 
    <ContentControl.Style> 
     <Style TargetType="{x:Type ContentControl}"> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding CurrentPage}" Value="{x:Static model:Pages.PageOne}"> 
         <Setter Property="ContentTemplate" Value="{StaticResource PageOneTemplate}"/> 
       </DataTrigger> 
       <DataTrigger Binding="{Binding CurrentPage}" Value="{x:Static model:Pages.PageTwo}"> 
        <Setter Property="ContentTemplate" Value="{StaticResource PageTwoTemplate}"/> 
       </DataTrigger>   
       <!-- And so on... -->  
      </Style.Triggers> 
     </Style> 
    </ContentControl.Style> 
</ContentControl> 

:

public enum Pages { 
    PageOne, 
    PageTwo, 
    // etc... 
} 

public class PageViewModel : ObservableObject { 
    private Pages currentPage = Pages.PageOne; 

    public PageViewModel() { 
     PageOneViewModel= new PageOneViewModel(Model); 
     PageTwoViewModel= new PageTwoViewModel(Model); 
     // And so on... 

     NavButtonCommand = new RelayCommand(NavButton); 
     PreviousButtonCommand = new RelayCommand(PreviousButton); 
    } 

    public PageModel Model { get; } = new PageModel(); 

    /// <summary>Gets or sets the current page.</summary> 
    public Pages CurrentPage { 
     get => currentPage; 
     set { 
      currentPage = value; 
      NotifyPropertyChanged(); 
     } 
    } 

    public DataSelectionViewModel PageOneViewModel { get; } 

    public ProfileSelectionViewModel PageTwoViewModel { get; } 

    public ICommand NavButtonCommand { get; } 

    public ICommand PreviousButtonCommand { get; } 

    // This isn't my actual page change logic, just some code with a 
    // similar effect to get my point across 
    private void NavButton(object param) { 
     int next = (int)CurrentPage + 1; 
     if Enum.IsDefined(typeof(Pages), next) { 
      CurrentPage = (Pages)next; 
     } 
    } 

    private void PreviousButton(object param) { 
     int previous = (int)CurrentPage - 1; 
     if Enum.IsDefined(typeof(Pages), previous) { 
      CurrentPage = (Pages)previous; 
     } 
    } 
} 

문제는 내보기의 일부, 내가 PropertyChanged 통지에 가입 할 필요를 그들의 각각의 ViewModels에 쉽게 바인딩 할 수없는 내 View의 내용을 변경할 수 있습니다. ContentControl이 매번 새로운 뷰를 생성하고 ViewModel에서 여전히 참조를 갖는 이벤트 핸들러로 인해 결코 정리되지 않기 때문에 "메모리 누수"가 발생합니다 (C#에서 메모리 누수가 발생할 수있는 한).

View가 변경 될 때 ViewModel에 대한 모든 이벤트 구독자를 정리했지만 ViewModel 내부에서보기 정리 코드가 발생한다는 사실과는 별개로 의도하지 않은 결과가 발생하여 일부 기능이 작동하지 않게되었습니다 .

내 의견을 말하면서 이벤트 구독을 중단 할 수있는 방법이 있습니까? 또는 바인딩 할 수있는 DependencyProperties를 사용하여 사용자 지정 컨트롤을 만드는 등의 방법으로 바인딩 할 방법을 찾아야합니다.

+0

보기 모델은 어떤 이벤트를 구독합니까? –

+0

뷰는 뷰 모델의 'PropertyChanged'알림을 구독합니다. – Lauraducky

+0

질문이 동일한 질문이므로 동일한 질문이 있다고 생각하지는 않지만 미래의 방문자가 비슷한 질문을 언급하는 데 도움이 될 수 있습니다. – Lauraducky

답변

1

나는 생각보다 빨리 대답을 찾았습니다. 대부분의 WPF 컨트롤이 수행하는 방식은 Weak Event Pattern입니다. 이 패턴을 사용하면 약한 참조로 이벤트를 구독 할 수 있습니다.

더 이런 일에
model.PropertyChanged += Model_PropertyChanged; 

:

PropertyChangedEventManager.AddHandler(model, Model_PropertyChanged, "MyProperty"); 

그런 식으로, 뷰 모델은보기보다 더 긴 수명을 경우에도, 모든 참조가 약한 것이 솔루션은이 같은 라인을 변경했다 이벤트 구독이 정리되지 않은 경우에도 가비지 수집기가 와서 개체를 정리할 수 있습니다.

+0

이 기사를 보시면 도움이 될 것입니다 : https://csharpvault.com/blog/weak-event-pattern/ – Arnel