У меня есть WCF-клиент, который передает Self-Tracking Entities в приложение WPF, созданное с помощью MVVM. Само приложение имеет динамический интерфейс. Пользователи могут выбирать, какие объекты они хотят видеть в своей рабочей области, в зависимости от того, какую роль они выполняют или какую задачу они выполняют.
Мои объекты самоконтроля имеют довольно много свойств навигации, и многие из них не нужны. Поскольку некоторые из этих объектов могут быть довольно большими, я бы хотел только загрузить эти свойства по запросу.
Мое приложение выглядит следующим образом:
[WCF] <---> [ClientSide Repository] <---> [ViewModel] <---> [View]
Мои модели - самоконтролируемые объекты. Клиентский репозиторий подключает метод LazyLoad (если необходимо), прежде чем возвращать модель в ViewModel, которая запросила его. Все вызовы службы WCF являются асинхронными, что означает, что методы LazyLoad также асинхронны.
Фактическая реализация LazyLoad дает мне некоторые проблемы. Вот варианты, которые я придумал.
EDIT - я удалил образцы кода, чтобы попытаться сделать это проще для чтения и понимания. См. Предыдущую версию вопроса, если вы хотите увидеть ее
Вариант A
Асинхронно LazyLoad свойства модели с сервера WCF в Getter
Хорошо: Загрузка данных по запросу чрезвычайно проста. Связывание в XAML загружает данные, поэтому, если элемент управления находится на экране, данные загружаются асинхронно и уведомляют пользовательский интерфейс, когда он там. Если нет, ничего не загружается. Например, <ItemsControl ItemsSource="{Binding CurrentConsumer.ConsumerDocuments}" />
будет загружать данные, однако если в разделе "Документы" интерфейса нет, то ничего не загружается.
Плохо: Нельзя использовать это свойство в любом другом коде до его запуска, потому что он вернет пустой список. Например, следующий вызов всегда будет возвращать false, если документы не были загружены.
public bool HasDocuments
{
get { return ConsumerDocuments.Count > 0; }
}
ОПЦИЯ B
Вручную сделайте вызов для загрузки данных при необходимости
Хорошо: Простота реализации - просто добавьте методы LoadConsumerDocumentsSync()
и LoadConsumerDocumentsAsync()
Плохо:. Не забудьте загрузить данные, прежде чем пытаться получить к нему доступ, в том числе, когда он используется в Bindings. Это может показаться простым, но оно может быстро выйти из-под контроля. Например, каждый ConsumerDocument имеет UserCreated и UserLastModified. Существует DataTemplate, который определяет UserModel с помощью всплывающей подсказки с дополнительными пользовательскими данными, такими как расширение, электронная почта, команды, роли и т.д. Таким образом, в моей модели ViewModel, которая отображает документы, мне нужно будет вызвать LoadDocuments
, затем прокрутите их и вызовите LoadConsumerModified
и LoadConsumerCreated
. Это тоже может продолжаться... после этого мне придется LoadUserGroups
и LoadUserSupervisor
. Он также подвержен риску циклических циклов, где нечто вроде User
имеет свойство Groups[]
, а Group
имеет свойство Users[]
ОПЦИЯ C
Мой любимый параметр пока... создайте два способа доступа к свойству. Одна синхронизация и одна асинхронная. Связывание будет выполнено с использованием свойства Async, и любой код будет использовать свойство Sync.
Хорошо: Данные загружаются асинхронно по мере необходимости. Именно то, что я хочу. Существует не так много дополнительного кодирования, так как все, что мне нужно сделать, это изменить шаблон T4 для создания этих дополнительных свойств/методов.
Плохо: Наличие двух способов доступа к одним и тем же данным кажется неэффективным и запутанным. Вам нужно будет запомнить, когда вы должны использовать Consumer.ConsumerDocumentsAsync
вместо Consumer.ConsumerDocumentsSync
. Существует также вероятность того, что вызов службы WCF запускается несколько раз, и для этого требуется дополнительное свойство IsLoaded для каждого навигационного свойства, такого как IsConsumerDocumentsLoaded.
ВАРИАНТ D
Пропустите загрузку Asyncronous и просто загрузите все синхронно в сеттерах.
Хорошо: Очень просто, без дополнительной работы
Плохо: Заблокирует пользовательский интерфейс при загрузке данных. Не хочу этого.
ВАРИАНТ E
Попросите кого-нибудь из SO сказать мне, что есть другой способ сделать это и указать мне на образцы кода:)
Другие заметки
Некоторые из параметров NavigationProperties будут загружены на сервер WCF до возврата объекта клиенту, однако другие из них слишком дороги для этого.
За исключением ручного вызова событий Load в Option C, все это можно сделать с помощью шаблона T4, поэтому для меня очень мало кодирования. Все, что мне нужно сделать, - это подключить событие LazyLoad в клиентском репозитории и указать его на правильные вызовы службы.