构建/解析ViewModels

时间:2013-03-21 00:53:27

标签: c# wpf design-patterns mvvm viewmodel

我正在处理的当前WPF项目需要一个复杂业务对象的查看器/编辑器。

首先,业务对象是“通用的”,因为它几乎没有继承 - 它们使用相同的底层域模型,但由于其(嵌套)属性的值,它们是不同的。

例如,假设业务对象是衍生衍生有大量其他嵌套业务对象,其中一个是 Legs的集合

Leg PROPERTIES 确定实际的 Derivative 。请记住,所有业务对象都是“包罗万象”(One Leg类,而不是LegA扩展基类LegBase。)

所以说“Derivative X”由两条腿组成, BOTH 的类型为 Leg 。一个人有一个属性说LegType = LegAFunding,第二个腿有LegType = CallableBlahh。

问题是不同的 Derivatives 需要不同的屏幕,但它们可能有相同的Legs,目的是你看不到某些类型的某些属性,而对于其他人你需要一些特殊的属性等。

是否存在构建或解析视图模型的“通用”模式,以便在明天发布新的Derivative时,我们可以使用构建器或工厂为其解析视图模型?有一个我们可以解决的默认视图模型会很棒,如果需要,我们可以扩展一个包含我们需要的基本属性集的正确视图模型,添加我们想要绑定/编辑/查看的额外属性,并合并它进入建筑商或工厂;该新衍生产品的视图将在视图模型中具有额外属性。

这是关于构建视图模型的一种控制反转,但我们的解决策略很复杂,并且对于我们正在解决的各种视图模型会有所不同。

有什么想法吗? This Webpage将这些类型的概念描述为“对象池”和“身份地图”等,但我找不到关于这些概念的任何信息,除了他们在该网站上的模糊想法和描述。

Psuedo代码:

public interface IViewModelFactoryProvider
{        
    // TBVM is the base view model you want and TM is the model you're 'wrapping'
    IViewModelFactory<TBVM, TM> GetViewModelFactory<TBVM, TM>()
        where TBVM : IViewModelBase;
}


public class ViewModelFactoryProvider
    : IViewModelFactoryProvider
{
    private readonly IUnityContainer container;

    public ViewModelFactoryProvider(IUnityContainer container)
    {
        this.container = container;

        RegisterFactories(container);
    }

    private static void RegisterFactories(IUnityContainer container)
    {
        container.RegisterType<IViewModelFactory<LegSummaryViewModel, Leg>, LegSummaryViewModelFactory>();
        // etc...
    }

    public IViewModelFactory<TBVM, TM> GetViewModelFactory<TBVM, TM>()
        where TBVM : IViewModelBase
    {
        // abstract away resolution from container
        return container.Resolve<IViewModelFactory<TBVM, TM>>();
    }
}


public class FundingLegSummaryViewModelFactory
    : BaseViewModelFactory<FundingLegSummaryViewModel, Leg>
{
    public FundingLegSummaryViewModelFactory(IUnityContainer container)
        : base(container)
    {
    }

    public override FundingLegSummaryViewModel CreateViewModel(Derivative deriv, Leg model)
    {
        var legType = model.LegType;
        switch (legType)
        {
            /*
            case "ThisFundingLegType":
                return container.Resolve<ThisFundingLegTypeSummaryViewModel>(new ResolverOverride[]
                    {
                        new ParameterOverride("deriv", deriv)
                    });
             */
            // I always have a default, new derivative, no problem...
            default:
                return container.Resolve<FundingLegSummaryViewModel>(new ResolverOverride[]
                    {
                        new ParameterOverride("deriv", deriv)
                    });
        }
    }
}

在Derivate ViewModel中使用以解析Leg ViewModel:

foreach (var leg in model.Legs)
{
    // I want a LegSummaryViewModel, don't care which one...the factory should resolve it for me...There is another LegSummaryViewModelFactory that based on one property uses a specific leg factory, above you see FundingLegSummaryViewModelFactory as one of these.
    var legSummaryViewModel = viewModelFactoryProvider
                    .GetViewModelFactory<LegSummaryViewModel, Leg>()
                    .CreateViewModel(model, leg);

    LegSummaries.Add(legSummaryViewModel);
}

注意:

请注意,我认为这是过度设计,或者更确切地说,使用Unity / DI可以做得更好。也许有一个enum / enum-strings,容器可以在某个地方引导,每个viewmodel类型(Derivative,Leg,Details,so)都可以像这样注册:

container.RegisterType<IViewModelBase, SpecificLegSummaryViewModelForTradeTypeAndLegType>(ViewModelTypes.LegSummaryViewModel);

这可以让我灵活地使用区域(Prism)。

1 个答案:

答案 0 :(得分:0)

首先,不要依赖ViewModel作为基础实体。或多或少,WPF中的ViewModel与视图相结合。例如命令等。它将减少模块化。

接下来,你说Leg类是某种通用的,然后我假设它可以很容易地使用接口设计。使用接口作为参数而不是类,因为它将增加模块性。

确保使用界面设计业务逻辑。有了它,无论你正在制作什么样的腿,只要你实现了正确的接口,它就会很好用。考虑使用依赖注入,它将适用于这种情况。

如果你提供一些你的通用Leg类及其衍生物的例子,你可以在这里找到更好的答案甚至是例子。

EDIT1:

现在问题比以前更清楚了。但是,我的假设是你需要根据给定的Leg类的类型创建一个视图模型。我将尝试根据Mark Seeman的抽象工厂模式提供一些示例,基于他的答案here

首先,解决方案的核心在于AbstractFactory。这里有2种模式: 一个。逻辑在于工厂,它将检查正确的ViewModel返回。湾逻辑在解析器中处理,以返回正确的Factory。但是,我将尝试使用(a。)逻辑提供解决方案。

public class LegVMFactory: ILegVMFactory{
  private readonly ILeg leg;
  public LegFactory(ILeg _leg){
    if(_leg == null) throw new Exception(""); //throw any exception you feel proper here
    this.leg = _leg;
  }
  public ILegViewModel Create(){
    if(leg is Leg){
      return new LegViewModel();
    }
    else if(leg is LegV1){
      return new LegV1ViewModel();
    }
    else if(leg is LegV2){
      return new LegV2ViewModel();
    }
    // and so on
  }
}

然后用法(简单逻辑):

Leg leg = new Leg();
LegVMFactory legVmFactory = new LegVMFactory(leg);
ILegViewModel legVM = legVmFactory.Create();