1

我有使用视图显示属性的长寿模型。我视图上的 DataContext 是一个寿命很短的 ViewModel。

示例包括列表中的行视图模型。

为了避免内存泄漏,视图模型使用System.Windows.WeakEventManager.

如果我要正常订阅,长寿模型将使视图模型保持活力。

在几乎每个视图模型中使用 Wea​​kEventManager 似乎非常麻烦。用例看起来像 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 订阅不计入视图模型的生命周期和取消订阅销毁的组合 - 或者更好的解决方案。

4

1 回答 1

1

我认为父视图模型应该负责摆脱引用。

这是一个将更新推送到每个子视图模型的简单示例。当一个孩子需要清理时,它会告诉父母删除它的引用。

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");
        }
    }
}
于 2018-10-02T11:33:20.937 回答