MvvmLight: Как отписаться от события «RaisePropertychanged» - PullRequest
0 голосов
/ 14 февраля 2020

У меня проблема в приложении WPF с MvvmLight.

Мое приложение:

  • У меня есть MainView с меню, каждый MenuItem открывается новый вид (различный для каждого элемента меню).
  • Каждый MenuItem привязан к RelayCommand моей MainViewModel
  • В моей MainViewModel RelayCommand просто делает Messenger.Default.Send(this, "ShowMyView") для MainView.
  • В моем MainView я зарегистрирован в сообщении «ShowMyView» и выполняются следующие действия:

var v = new MyView(); v.Owner = this; v.ShowDialog(); Messenger.Default.Unregister(v);

Этот новый вид (MyView) привязан к модели представления (MyViewModel), который содержит свойства. Элементы этого представления (текстовое поле, radiobutton и т. Д. c) связаны с этими свойствами.

Когда я закрываю «MyView», он удаляется, и я возвращаюсь к своему основному виду, но «MyViewModel» все еще существует.

Проблема:

Когда я впервые открываю «MyView», привязка работает правильно, если «MyViewModel» устанавливает свойство, вызывается RaisePropertyChanged, затем «get» этого свойства вызывается один раз.

Но если я открываю и закрываю свое представление 20 раз, то в 20-й раз, когда вызывается RaisePropertyChanged, получение этого свойства вызывается 20 раз!

Вопрос:

Так как я могу отменить подписку на эти "RaisePropertyChanged", когда я закрываю представление?

Прыжки для вас понятны, и извините за мой плохой английский sh.

РЕДАКТИРОВАТЬ: С кодом

РЕДАКТИРОВАТЬ BIS

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

https://github.com/damgot/MvvmLightProblemExample

Когда я запускаю приложение, запускается MainWindow:

enter image description here

Вы можете увидеть в выводе отладки:

Starting
Creating NewViewModel

Затем, когда я нажимаю на NewView Menu, открывается новое представление:

enter image description here

И вы можете увидеть в выводе отладки:

Initialize NewViewModel and set MyBool to true
MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call

Кажется, хорошо, поскольку у меня есть 2 переключателя, привязанные к «MyBool»

Теперь, если я выберу «MyBool is false», переключатель:

enter image description here

и в выводе:

MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call

Все еще хорошо.

Теперь, если я закрою NewView, открою его снова и выберу кнопку «MyBool is false», вывод:

MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call

Затем снова вывод:

MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call

и еще раз:

MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call

И так далее ...

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

Ответы [ 2 ]

0 голосов
/ 17 февраля 2020

Я нашел другое решение, более красивое, чем первое опубликованное мной решение.

В моем ViewModelLocator я удалил все свойства viewmodel. И вместо этого я создал эту функцию c:

public static T GetViewModelInstance<T>(Window w)
{
    var uniqueKey = System.Guid.NewGuid().ToString();
    T VMInstance = ServiceLocator.Current.GetInstance<T>(uniqueKey);
    w.Closed += (sender, args) => SimpleIoc.Default.Unregister(uniqueKey);
    return VMInstance;
}

Итак, как вы можете видеть, я не возвращаю ViewModel, а создаю новый его экземпляр (с ключом uniqueKey). И я зарегистрировался в закрытом событии вызывающего представления, чтобы отменить регистрацию созданного экземпляра виртуальной машины.

Я больше не определяю DataContext в xaml, но в конструкторе xaml.cs я устанавливаю DataContext следующим образом:

DataContext = ViewModelLocator.GetViewModelInstance<NewViewModel>(this);

И это работает довольно хорошо.

0 голосов
/ 16 февраля 2020

Я нашел решение, но оно уродливое.

Как я уже сказал в комментарии, я не одинок в своем проекте, и решение включало другой проект, который я не могу редактировать. Поэтому я не могу просто подавить «ViewModelLocator».

Поэтому, чтобы исправить мою проблему, в моем ViewModelLocator, в моих свойствах ViewModels, вместо этого:

public NewViewModel NewView
{
    get
    {
        var vm = ServiceLocator.Current.GetInstance<NewViewModel>();
        vm.Initialize();
        return vm;
    }
}

Я делаю это:

public NewViewModel NewView
{
    get
    {
        SimpleIoc.Default.Unregister<NewViewModel>();
        SimpleIoc.Default.Register<NewViewModel>(true);
        var vm = ServiceLocator.Current.GetInstance<NewViewModel>();
        vm.Initialize();
        return vm;
    }
}

Каждый раз, когда я вызываю ViewModel (поэтому, когда я открываю представление), модель незарегистрированная, а затем регистрируется. Это заставляет воссоздать ViewModel, поэтому все подписки на PropertyChanged сбрасываются.

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

...