我如何告诉我的视图何时应该取消订阅事件?

劳拉达基

我正在使用 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>

底层 ViewModel 看起来像这样:

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它们各自 ViewModel 上的通知,以便我可以更改视图中无法轻松绑定的内容。这会导致“内存泄漏”(就 C# 中可能存在的内存泄漏而言),因为ContentControl它每次都会创建一个新的 View,并且由于这些事件处理程序在 ViewModel 中仍然具有引用,因此它永远不会被清除。

我尝试在 View 更改时清理 ViewModel 的所有事件订阅者,但除了会导致 ViewModel 中的视图清理代码这一事实之外,它还产生了意想不到的后果,并使我的一些功能停止工作。

有没有办法告诉我的观点停止订阅事件?或者,我是否应该找到一种方法来绑定它们(例如使用可以绑定的 DependencyProperties 创建自定义控件)。

劳拉达基

我找到了答案,比我想象的要快。大多数 WPF 控件执行此操作的方式是Weak Event Pattern此模式允许您使用弱引用订阅事件。解决方案是改变这样的行:

model.PropertyChanged += Model_PropertyChanged;

更像这样的事情:

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

这样,即使 ViewModel 的生命周期比视图长,任何引用也只是弱引用,允许垃圾收集器来清理对象,即使它的事件订阅还没有被清理。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章