Предотвращение WeakEventManager и утечек памяти на недолговечных моделях представления - PullRequest
0 голосов
/ 25 сентября 2018

У меня есть долгоживущие модели, свойства которых отображаются в виде.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, что подписки делаютне рассчитывать на срок службы модели представления и отмены подписки на уничтожение - или даже лучшее решение.

1 Ответ

0 голосов
/ 02 октября 2018

Я думаю, что родительская модель представления должна отвечать за избавление от ссылок.

Это простой пример, который выдвигает обновление для каждой дочерней модели представления.Когда ребенок нуждается в очистке, он говорит родителю удалить свою ссылку.

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");
        }
    }
}
...