Разрешить ViewModels для коллекции (разных типов) моделей - PullRequest
0 голосов
/ 24 января 2012

Я немного запутался в паттерне MVVM, который я комбинирую с PRISM.Вкратце: я пытаюсь создать представления и модели представления на основе существующих моделей, которые создаются отдельным сервисом.Сервис не знает и не должен ничего знать о видах и / или моделях видов.Этот сервис создает модели разных типов, для простоты давайте назовем их SquareModel и CircleModel.Все эти типы имеют одну и ту же абстрактную BaseModel.Предположим, что служба генерирует список типа BaseModel с квадратными и круговыми моделями.Теперь вопрос в том, как я перевожу эти Модели в соответствующие ViewModels и помещаю их в новый список.Каждый тип должен иметь свою собственную модель представления;так:

  • SquareModel -> SquareViewModel
  • CircleModel -> CircleViewModel

Это связано с тем, что обе модели предоставляют разные свойства, которые я хочу связать с помощьюViewModel.Кроме того, как мне объединить эти два типа ViewModel в один список для представления моему представлению?

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

Для созданиявсе более понятно, я собрал пример кода, показанного ниже, чтобы показать, что я сделал.Первый подход - через переключение типа, второй - использование ExportFactory из MEF 2.0.И то, и другое терпит неудачу, причина в коде.Я действительно ценю любую помощь!

/*
 * Models (these are generated by a service, the service doesn't and should not now about views or view models)
 * 
 * 
 */

abstract class BaseModel { }

class SquareModel : BaseModel { }

class CircleModel : BaseModel { }


/*
 *  View Models
 * 
 * 
 */

abstract class BaseViewModel<TModel> // : INOtificationPropertyChanged, etc
{
    protected TModel Model;

    public void SetModel(TModel model)
    {
        Model = model;
        OnChangeModel();
    }

    protected virtual void OnChangeModel()
    {
        // Assignment of base properties here, based on Model
    }

    // Declarate some base properties here
}

[Export(typeof(BaseViewModel<BaseModel>))]
[TypeMetadata(Type = "CircleViewModel")]
class CircleViewModel : BaseViewModel<CircleModel>
{
    protected override void OnChangeModel()
    {
        // Assignment of circle specific properties here, based on Model
    }

    // Declarate some circle specific properties here
}

[Export(typeof(BaseViewModel<BaseModel>))]
[TypeMetadata(Type = "SquareViewModel")]
class SquareViewModel : BaseViewModel<SquareModel>
{
    protected override void OnChangeModel()
    {
        // Assignment of square specific properties here, based on Model
    }

    // Declarate some square specific properties here
}

class Program
{
    [ImportMany]
    protected IEnumerable<ExportFactory<BaseViewModel<BaseModel>, ITypeMetadata>> Factories { get; set; }

    public BaseViewModel<BaseModel> Create(string viewModelType)
    {
        var factory = (from f in Factories where f.Metadata.Type.Equals(viewModelType) select f).First();

        // Factory is able to create View Models of type viewModelType using CreateExport() function
        var vm = factory.CreateExport().Value;

        return vm;
        // Same error as with solution A
        // cannot convert from 'ConsoleApplication1.SquareViewModel' to 'ConsoleApplication1.BaseViewModel<ConsoleApplication1.BaseModel>'
        // This error is actually displayed in ExportFactory context, but it means the same
    }

    public BaseViewModel<BaseModel> CreateFrom(Type type)
    {
        var vmTypeName = type.Name + "ViewModel";
        return Create(vmTypeName);
    }

    public BaseViewModel<BaseModel> CreateVMUsingExportFactory(BaseModel model)
    {
        var vm = CreateFrom(model.GetType());
        vm.SetModel(model);
        return vm;
    }

    public void DoStuff()
    {
        // Suppose service gives me this
        var serviceOutput = new List<BaseModel>
                                {
                                    new SquareModel(),
                                    new CircleModel(),
                                    new CircleModel(),
                                    new SquareModel(),
                                    new CircleModel(),
                                    new SquareModel(),
                                    new SquareModel()
                                    // may be longer but not the point
                                };

        // viewModelCollection is bound to a listbox, by using datatemplates everthing is nicely placed on the canvas; no problem there
        // Actually this is a ObserveableCollection
        List<BaseViewModel<BaseModel>> viewModelCollection = new List<BaseViewModel<BaseModel>>();


        //
        // What to do here?
        //

        //
        // A. Switch-on-type
        foreach (var model in serviceOutput)
        {
            // Note there are beter implementations of this, using dicationaries and delegates, main goal of that is to not break when refactoring;
            switch (model.GetType().Name)
            {
                case "SquareModel":
                    SquareViewModel vm = new SquareViewModel();
                    vm.SetModel((SquareModel)model); // another cast..... :(
                    viewModelCollection.Add(vm);
                    // Error: 
                    // cannot convert from 'ConsoleApplication1.SquareViewModel' to 'ConsoleApplication1.BaseViewModel<ConsoleApplication1.BaseModel>'

                    break;

                case "CircleModel":
                    // same
                    break;
            }
        }

        // B. MEF ExportFactory<>
        //
        foreach (var model in serviceOutput)
        {
            var vm = CreateVMUsingExportFactory(model);
            viewModelCollection.Add(vm);
        }

        // C. Something else?!
        //
        // Please help ;-).
    }

a

1 Ответ

2 голосов
/ 25 января 2012

привязка xaml очень проста с типом объекта, вы можете использовать объект вместо определения типа

Если у вас возникли проблемы с вашим кодом таблицы данных (который не должен быть проблемой), используйте следующее

List<object> viewModelCollection = new List<object>(serviceOutput.Select(model=> CreateVMUsingExportFactory(model) as object));

Вышесказанное использует linq и lambda для создания списка объектов.

...