ViewModel Регистрация событий и ViewModel Lifetime - PullRequest
1 голос
/ 09 февраля 2012

У меня архитектурная проблема, и возможное решение, на которое мне хотелось бы получить мнение.

Я привык к архитектуре MVVM для WP7 (когда это возможно, но, к сожалению, иногда SDK, кажется, идет наоборотнаправление).

WP7 форсирует подход ViewFirst, и я чувствую себя комфортно с этим (за исключением части, в которой мы не можем переопределить создание представления, как в Silverlight, чтобы сделать возможным внедрение конструктора).Я чувствовал себя уверенно, когда большинство моделей представления следовало за временем его просмотра.Таким образом, viewmodel создается при создании представления (путем доступа к ViewModelLocator), на ViewModel ссылаются (или должны) ссылаться только его представления, когда представление уничтожается, и его ViewModel должна быть уничтожена (это не обязательно, но это путь).я иду, за исключением очень редкого случая, для которого я создаю одноэлементную модель просмотра).

Моей модели представления может потребоваться регистрация на некоторые события одноэлементной службы (телефонный сервис или созданный мной одноэлементный класс).Я имею в виду, что может потребоваться регистрация на событие класса, время жизни которого не определяется самой моделью представления.Эти события сохраняют жесткую привязку к моей модели представления и поддерживают мою модель просмотра, даже когда представление уничтожено, не только моя модель представления будет продолжать получать и обрабатывать события.Шаблон WeakEvent может быть возможным решением, но невозможно создать менеджер событий для каждого события.Лучшее решение, на мой взгляд, не существует и должно быть ключевым словом для слабой регистрации событий.

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

Другой возможный способ (я не проверял) мог бы сделать мою модель представлениязнать о завершении финализации и выполнять некоторую очистку, когда представление завершено, но у меня всегда было чувство, что этот подход не рекомендуется из-за использования финализации.Кроме того, мне не ясно, насколько сильно это повлияет на производительность.

Что вы думаете о том, чтобы время жизни модели представления совпадало с ее видом (оно до сих пор всегда упрощало мое приложение)?Что вы думаете о решении NavigateTo-NavigateFrom ViewModel?Что вы думаете о решении View-Finalization ViewModel?Испытывали ли вы какое-либо из этих или, возможно, решение другого типа?

С уважением, SkyG

ОБНОВЛЕНИЕ

Я обнаружил, что решение для финализации не будет выполнятьработа, потому что это может произойти в конце будущего (или, возможно, никогда).На данный момент мне кажется, что лучшим решением является пара виртуальных методов в инициализации и очистке viewmodelbase для отмены регистрации регистрации событий, которую должно вызвать представление.Возможный момент для их вызова может быть во время загруженного и выгруженного события (когда мне не нужна моя модель представления, обрабатывает событие, если я нахожусь в последующем представлении, в этом случае первая модель представления / представления все еще жива в backstack, нозагруженные / выгруженные запускаются, если они видят, прикреплен / отсоединен к визуальному дереву).

Любое другое мнение (даже положительное) будет оценено.

Спасибо

Ответы [ 2 ]

1 голос
/ 10 февраля 2012

Я согласен, что идея слабого события хороша, но она была бы слишком громоздкой для реализации.Он также создает свои собственные проблемы - он может сделать view-модель совершенно слабой ссылкой, что делает его кандидатом на сборку мусора прежде, чем он действительно «должен» (мнение разработчика против мнения сборщика мусора).Я был укушен этим раньше, как и Уорд Белл в этом сообщении в своем блоге о .

На основании ваших требований и желания следовать «чистому» подходу к MVVM (viewmodel не делаетЯ знаю, что вы боретесь с балансом между «представлением» и «моделью» модели представления.В этом случае я бы на самом деле предложил другой шаблон проектирования: MVPVM (модель / представление / презентатор / представление-модель).Вот статья MSDN об этом.

В вашем случае, ведущий будет удерживать эти одиночные события.Для докладчика было бы хорошо знать о представлении, потому что докладчик не предназначен для повторного использования в представлениях.Тогда ваша модель представления станет просто «моделью представления», позволяющей многократно использовать и устранять большинство проблем с жизненным циклом виртуальной машины.

Мне нравится подход MVPVM, потому что он всегда меня интересовал в MVVM, когда мои модели обзора тоже начали приобретатьбольшая ответственность (общение со слоем доступа к данным, прослушивание событий всего приложения, а также обработка команд из представления, поддержание его свойств для представления и т. д.).Я знаю, что это не обязательно ответ на ваш вопрос, но это слишком долго для комментария.

1 голос
/ 09 февраля 2012

Что вы думаете о том, чтобы время жизни модели представления было таким же, как и у ее представления (оно до сих пор всегда упрощало мое приложение)?

Для меня это звучит разумно, так как это напрямую связанона DataContext вида.

Что вы думаете о решении с NavigateTo-NavigateFrom ViewModel?

Не думаю, что это хорошая идея.В шаблоне MVVM предполагается, что ViewModels ничего не знает о представлении.Навигация, как правило, связана с представлениями, поэтому я не думаю, что это лучшая идея.

Что вы думаете о решении View-Finalization ViewModel с поддержкой View-Finalization?

БезГоворя о финализации, метод очистки для моделей представлений - это IMO.В базовом классе для всех ваших ViewModels (надеюсь, у вас есть) вы можете поместить следующий метод:

public abstract class ViewModelBase
{
    ....
    public virtual void Cleanup();
}

Затем просто вызовите myViewModel.CleanUp();, когда ваше представление закрыто.Отмените регистрацию ваших событий в конкретной реализации CleanUp:

public override void CleanUp()
{
    ....Event -= this....EventHandler;
}
...