我正在使用 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] 删除。
我来说两句