避免 WeakEventManager 和短期视图模型上的内存泄漏
Avoiding WeakEventManager and memory leaks on short lived viewmodels
我有长期使用视图显示属性的模型。
我视图中的 DataContext 是一个寿命较短的 ViewModel。
示例包括列表中的行视图模型。
为避免内存泄漏,视图模型使用 System.Windows.WeakEventManager
.
订阅模型
如果我正常订阅,长寿模型将使视图模型保持活动状态。
在几乎每个视图模型中使用 WeakEventManager 似乎非常麻烦。
用例看起来像 WPF 的标准用例。我是否缺少 WPF 或 C# 的基本概念来帮助我在此处编写更好的代码?
这是一个最小的例子,说明了我现在所做的事情。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//building would take place in a factory method
DataContext = new ShortLivedViewModel(new LongLivingModel());
}
}
public class ShortLivedViewModel : INotifyPropertyChanged
{
private string _myText;
public ShortLivedViewModel(LongLivingModel model)
{
model.SomeEvent += SomeEventHandler;
WeakEventManager<LongLivingModel, EventArgs>.AddHandler(model, nameof(LongLivingModel.SomeEvent),
SomeEventHandler);
}
public string MyText
{
get => _myText;
set
{
_myText = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MyText)));
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void SomeEventHandler(object sender, EventArgs e)
{
//The actual update content would come from the event args
MyText = Guid.NewGuid().ToString("N");
}
}
public class LongLivingModel
{
//the event does not matter too much so I omit the implementation that causes it
public EventHandler<EventArgs> SomeEvent = delegate { };
}
我的问题是,是否有一种不那么麻烦的方法可以从短寿命对象订阅长寿命对象。或者如果 WPF 中有一些我为此缺少的工具。
我觉得这是标准情况。
我玩的是添加一个 IDisposable
接口,但这只是让我知道何时调用 dispose 以便我可以取消订阅。
我正在寻找的可能是告诉 GC 订阅不计入视图模型的生命周期和取消订阅销毁的组合 - 或者更好的解决方案。
我认为 parent 视图模型应该负责删除引用。
这是一个将更新推送到每个 child 视图模型的简单示例。当 child 需要清理时,它告诉 parent 删除它的引用。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//building would take place in a factory method
DataContext = new LongLivingModel();
LongLivingModel.AddChild();
LongLivingModel.AddChild();
}
}
public class ShortLivedViewModel : INotifyPropertyChanged
{
private readonly LongLivingModel longLivingModel;
public ShortLivedViewModel(LongLivingModel longLivingModel){
this.longLivingModel = longLivingModel;
}
private string _myText;
public string MyText
{
get => _myText;
set
{
_myText = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MyText)));
}
}
public void Remove(){
longLivingModel.Remove(this);
}
// INotifyPropertyChanged implementation
}
public class LongLivingModel
{
public ObservableCollection<ShortLivedViewModel> ChildViewModels { get; } = new ObservableCollection<ShortLivedViewModel>();
public void AddChild(){
ChildViewModels.Add(new ShortLivedViewModel(this));
}
public void RemoveChild(ShortLivedViewModel shortLivedViewModel) {
ChildViewModels.Remove(shortLivedViewModel);
}
public void PushToChildren(){
foreach(ShortLivedViewModel shortLivedViewModel in ChildViewModels){
shortLivedViewModel.MyText = Guid.NewGuid().ToString("N");
}
}
}
我有长期使用视图显示属性的模型。 我视图中的 DataContext 是一个寿命较短的 ViewModel。
示例包括列表中的行视图模型。
为避免内存泄漏,视图模型使用 System.Windows.WeakEventManager
.
如果我正常订阅,长寿模型将使视图模型保持活动状态。
在几乎每个视图模型中使用 WeakEventManager 似乎非常麻烦。 用例看起来像 WPF 的标准用例。我是否缺少 WPF 或 C# 的基本概念来帮助我在此处编写更好的代码?
这是一个最小的例子,说明了我现在所做的事情。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//building would take place in a factory method
DataContext = new ShortLivedViewModel(new LongLivingModel());
}
}
public class ShortLivedViewModel : INotifyPropertyChanged
{
private string _myText;
public ShortLivedViewModel(LongLivingModel model)
{
model.SomeEvent += SomeEventHandler;
WeakEventManager<LongLivingModel, EventArgs>.AddHandler(model, nameof(LongLivingModel.SomeEvent),
SomeEventHandler);
}
public string MyText
{
get => _myText;
set
{
_myText = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MyText)));
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void SomeEventHandler(object sender, EventArgs e)
{
//The actual update content would come from the event args
MyText = Guid.NewGuid().ToString("N");
}
}
public class LongLivingModel
{
//the event does not matter too much so I omit the implementation that causes it
public EventHandler<EventArgs> SomeEvent = delegate { };
}
我的问题是,是否有一种不那么麻烦的方法可以从短寿命对象订阅长寿命对象。或者如果 WPF 中有一些我为此缺少的工具。
我觉得这是标准情况。
我玩的是添加一个 IDisposable
接口,但这只是让我知道何时调用 dispose 以便我可以取消订阅。
我正在寻找的可能是告诉 GC 订阅不计入视图模型的生命周期和取消订阅销毁的组合 - 或者更好的解决方案。
我认为 parent 视图模型应该负责删除引用。
这是一个将更新推送到每个 child 视图模型的简单示例。当 child 需要清理时,它告诉 parent 删除它的引用。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//building would take place in a factory method
DataContext = new LongLivingModel();
LongLivingModel.AddChild();
LongLivingModel.AddChild();
}
}
public class ShortLivedViewModel : INotifyPropertyChanged
{
private readonly LongLivingModel longLivingModel;
public ShortLivedViewModel(LongLivingModel longLivingModel){
this.longLivingModel = longLivingModel;
}
private string _myText;
public string MyText
{
get => _myText;
set
{
_myText = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MyText)));
}
}
public void Remove(){
longLivingModel.Remove(this);
}
// INotifyPropertyChanged implementation
}
public class LongLivingModel
{
public ObservableCollection<ShortLivedViewModel> ChildViewModels { get; } = new ObservableCollection<ShortLivedViewModel>();
public void AddChild(){
ChildViewModels.Add(new ShortLivedViewModel(this));
}
public void RemoveChild(ShortLivedViewModel shortLivedViewModel) {
ChildViewModels.Remove(shortLivedViewModel);
}
public void PushToChildren(){
foreach(ShortLivedViewModel shortLivedViewModel in ChildViewModels){
shortLivedViewModel.MyText = Guid.NewGuid().ToString("N");
}
}
}