Silverlight с наследованием MVVM: ModelView и представление, соответствующие модели - PullRequest
2 голосов
/ 13 апреля 2010

Сегодня у меня есть специальный вопрос о Silverlight (4 RC) MVVM и концепциях наследования, и я ищу наилучшее практическое решение ... Я думаю, что я понимаю основную идею и концепции MVVM. Моя модель ничего не знает о ViewModel , так как сама ViewModel сама не знает о View . ViewModel знает Модель и Представления знает ViewModels .

Представьте себе следующий базовый (пример) сценарий (я пытаюсь сделать что-нибудь коротким и простым):

Моя модель содержит класс ProductBase с несколькими базовыми свойствами, SimpleProduct : ProductBase с добавлением нескольких дополнительных свойств и ExtendedProduct : ProductBase с добавлением других свойств. В соответствии с этой моделью у меня есть несколько моделей ViewModel, наиболее важные из которых SimpleProductViewModel : ViewModelBase и ExtendedProductViewModel : ViewModelBase. И последнее, но не менее важное, согласно представлениям SimpleProductView и ExtendedProductView. В будущем я мог бы добавить много типов продуктов (и соответствующие представления + виртуальные машины).

1. Как узнать, какую ViewModel создать при получении коллекции Model?
После вызова моего метода провайдера данных он, наконец, получит List<ProductBase>. Он содержит, например, один SimpleProduct и два ExtendedProducts. Как я могу преобразовать результаты в ObservableCollection<ViewModelBase> с правильными типами ViewModel (один SimpleProductViewModel и два ExtendedProductViewModels ) в нем?

I может проверить модель , напечатать и построить ViewModel соответственно, т.е.

foreach(ProductBase currentProductBase in resultList)
    if (currentProductBase is SimpleProduct)
      viewModels.Add(
        new SimpleProductViewModel((SimpleProduct)currentProductBase));

    else if (currentProductBase is ExtendedProduct)
      viewModels.Add(
        new ExtendedProductViewModels((ExtendedProduct)currentProductBase));
    ...
}

... но я считаю это очень плохой практикой, так как этот код не соответствует объектно-ориентированному дизайну. И наоборот, предоставление абстрактных методов Factory уменьшит код до:

foreach(ProductBase currentProductBase in resultList)
    viewModels.Add(currentProductBase.CreateViewModel())

и будет идеально расширяемым, но поскольку Model не знает ViewModels , это невозможно. Я мог бы привнести интерфейсы в игру здесь, но я еще не видел такой подход доказанным.

2. Как мне узнать, какой View отображать при выборе ViewModel?
Это почти та же проблема, но на более высоком уровне. В конечном итоге, получив желаемую коллекцию ObservableCollection<ViewModelBase>, потребуется, чтобы основной вид выбрал соответствующий Вид для ViewModel .

В WPF существует концепция DataTemplate, которая может предоставить View для определенного DataType . К сожалению, это не работает в Silverlight, и единственной заменой, которую я нашел, был ResourceSelector из SLExtensions инструментарий, который глючит и не удовлетворяет.

Кроме того, все проблемы из Вопроса 1 также применимы.

У вас есть какие-то подсказки или хотя бы решение проблем, которые я описываю, которые, я надеюсь, вы сможете понять из моего объяснения?

Заранее спасибо!

Thomas

1 Ответ

3 голосов
/ 13 апреля 2010

Я делаю такие вещи, чтобы сделать MVVM строго типизированным.

Я определяю некоторые базовые интерфейсы

public interface IModel
{
}

public interface IViewModel
{
}

public interface IViewModel<M> : IViewModel
    where M : IModel
{
    void Bind(M model);
}

public interface IView
{
}

public interface IView<VM> : IView
    where VM : IViewModel
{
    void Bind(VM viewModel);
}

Это обеспечивает основные отношения между моими моделями, модельными представлениями и представлениями.

Я создаю абстрактные реализации для IModel и универсальных IViewModel<> & IView<> интерфейсов.

public abstract class ModelBase : IModel
{
}

public abstract class ViewModelBase<M> : IViewModel<M>
    where M : IModel
{
    public abstract void Bind(M model);
}

public abstract class ViewBase<VM> : IView<VM>
where VM : IViewModel
{
    public abstract void Bind(VM viewModel);
}

Затем я использую их для определения реальных конкретных объектов - сначала с интерфейсами.

public interface IPersonModel : IModel
{
}

public interface IPersonViewModel : IViewModel<IPersonModel>
{
}

public interface IPersonView : IView<IPersonViewModel>
{
}

Обратите внимание, как наследование интерфейса блокируется в отношениях типов.

Теперь конкретные классы могут быть определены.

public class PersonModel : ModelBase, IPersonModel
{
}

public class PersonViewModel : ViewModelBase<IPersonModel>, IPersonViewModel
{
    public override void Bind(IPersonModel model)
    {
        throw new NotImplementedException();
    }
}

public class PersonView : ViewBase<IPersonViewModel>, IPersonView
{
    public override void Bind(IPersonViewModel viewModel)
    {
        throw new NotImplementedException();
    }
}

Таким образом, учитывая модель, я могу искать объект, который реализует IViewModel<M> для этой модели, и учитывая модель представления, я могу искать IView<VM> для этой модели представления.

Здесь можно использовать структуры для внедрения зависимостей.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...