ViewModel Регистрация событий и ViewModel Lifetime
У меня есть архитектурная проблема и возможное решение, по которому я хотел бы получить мнение.
Я привык к архитектуре 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 ответа
Что вы думаете о том, чтобы время жизни модели представления совпадало с ее видом (это всегда упрощало мое приложение до сих пор)?
Это звучит разумно для меня, так как это напрямую связано с DataContext
зрения.
Что вы думаете о решении NavigateTo-NavigateFrom ViewModel?
Я не думаю, что это хорошая идея. В шаблоне MVVM предполагается, что ViewModels ничего не знает о представлении. Навигация обычно связана с представлениями, поэтому я не думаю, что это лучшая идея.
Что вы думаете о решении View-Finalization ViewModel?
Не говоря уже о завершении, метод очистки для моделей представлений - это IMO. В базовом классе для всех ваших ViewModels (надеюсь, у вас есть) вы можете поместить следующий метод:
public abstract class ViewModelBase
{
....
public virtual void Cleanup();
}
Затем просто позвоните myViewModel.CleanUp();
когда ваш взгляд закрыт. Отмените регистрацию ваших событий в конкретной реализации CleanUp
:
public override void CleanUp()
{
....Event -= this....EventHandler;
}
Я согласен, что идея слабого события хороша, но она была бы слишком громоздкой для реализации. Он также создает свои собственные проблемы - он может сделать view-модель полностью слабой ссылкой, что делает его кандидатом на сборку мусора прежде, чем он действительно "должен" (мнение разработчика против мнения сборщика мусора). Я был укушен этим раньше, как и Уорд Белл в своем блоге.
Исходя из ваших требований и желания следовать "чистому" подходу к MVVM (viewmodel не знает о представлении), кажется, что вы боретесь с балансом между "представлением" и "моделью" представления. В этом случае я бы на самом деле предложил другой шаблон проектирования: MVPVM (модель / представление / презентатор / представление-модель). Вот статья MSDN об этом.
В вашем случае, ведущий будет держаться за эти одиночные события. Было бы хорошо, чтобы докладчик знал о представлении, потому что докладчик не предназначен для повторного использования в представлениях. Тогда ваша модель представления станет просто "моделью представления", что позволит использовать ее повторно и устранить большинство проблем с жизненным циклом виртуальной машины.
Мне нравится подход MVPVM, потому что он всегда интересовал меня в MVVM, когда мои модели представления стали брать на себя слишком большую ответственность (общение со слоем доступа к данным, прослушивание событий всего приложения, а также обработка команд из представления, поддержание его свойств для просмотр и т. д.). Я знаю, что это не обязательно ответ на ваш вопрос, но это слишком долго для комментария.