2012-07-19 46 views
2

我试图找出什么是正确的方式注入我的ViewModel ICommand注入命令到ViewModels

鉴于我的ViewModel看起来像这样。

public class ViewModel : IViewModel 
{ 
    ICommand LoadCommand { get; } 
    ICommand SaveCommand { get; } 
} 

我目前做这在我的构造

public ViewModel(IRepository repository, IErrorLog errorLog, IValidator validator) 
{ 
    LoadCommand = new LoadCommandImpl(repository, errorLog); 
    SaveCommand = new SaveCommandImpl(repository, errorLog, validator); 
} 

注意,参数不从构建的命令所使用的视图模型可言,一边。

当我试图遏制尽可能多的逻辑尽可能的注入接口,还有在命令逻辑。

这似乎更适合做这个

public ViewModel(ICommand loadCommand, ICommand saveCommand) 
{ 
    LoadCommand = loadCommand; 
    SaveCommand = saveCommand; 

    LoadCommand.SetViewModel(this); 
    SaveCommand.SetViewModel(this); 
} 

但是要做到这一点,我需要让我的统一登记这样。这不是世界末日,但它似乎是一种痛苦。

container.RegisterType<ICommand, LoadCommandImpl>("loadCommand"); 
container.RegisterType<ICommand, SaveCommandImpl>("saveCommand"); 

container.RegisterType<IViewModel, ViewModel>(
    new InjectionConstructor(
     new ResolvedParameter<ICommand>("loadCommand"), 
     new ResolvedParameter<ICommand>("SaveCommand"))); 

或者,我可以让ILoadCommandISaveCommand接口,而这些接口将是空的或可能实施ICommand

我不是任何这些解决方案的巨大粉丝。这里推荐的方法是什么?

编辑回应blindmeis

让我们假设这是比一时的命令以外的东西。

public ViewModel(IFoo foo) 
{ 
    Bar = new Bar(foo); 
} 

在我看来,这将只是注入伊巴尔

public ViewModel(IBar bar) 
{ 
    Bar = bar; 
} 

更合适但现在我有Bar1Bar2。所以,我可以做

public ViewModel(IFoo foo) 
{ 
    Bar1 = new Bar1(foo); 
    Bar2 = new Bar2(foo); 
} 

public ViewModel(IBar bar1, IBar bar2) 
{ 
    Bar1 = bar1; 
    Bar2 = bar2; 
} 
+1

你为什么要在所有注入ICommand的?视图模型的一个目的是揭露viewlogic。如果你想注入一个messageboxservice或类似的东西 - 我和你在一起,但是一个命令属于viewmodel。或者你想以任何方式重用这些命令? – blindmeis 2012-07-20 06:38:58

+0

@blindmeis一些命令可以重复使用。但这是我的问题的重点。如果我只是为了将它们传递给命令而注入参数,我应该注入命令吗? – cadrell0 2012-07-20 12:20:49

+3

是的,你应该传递命令而不是参数来保持最大的灵活性。例如传入命令将允许您模拟Command对象进行测试。进一步传递命令还将允许您在将来以不同方式构建命令,例如允许每个命令记录到不同的错误日志。每个对象都应负责接收自己的参数并构建其对象图。将参数传递给您的视图模型会带来什么好处? – caa 2012-07-20 14:49:56

回答

1

这种行为是不包含在统一,但它不是很难改造。

var container = new UnityContainer(); 
container.AddNewExtension<MapParameterNamesToRegistrationNamesExtension>(); 
container.RegisterType<ICommand, LoadCommand>("loadCommand"); 
container.RegisterType<ICommand, SaveCommand>("saveCommand"); 
container.RegisterType<ViewModel>(new MapParameterNameToRegistrationName()); 
var vm = container.Resolve<ViewModel>(); 
Assert.IsType(typeof(LoadCommand), vm.LoadCommand); 
Assert.IsType(typeof(SaveCommand), vm.SaveCommand); 

public class MapParameterNamesToRegistrationNamesExtension : UnityContainerExtension 
{ 
    protected override void Initialize() 
    { 
    var strategy = new MapParameterNamesToRegistrationNamesStrategy(); 
    this.Context.Strategies.Add(strategy, UnityBuildStage.PreCreation); 
    } 
} 
public class MapParameterNamesToRegistrationNamesStrategy : BuilderStrategy 
{ 
    public override void PreBuildUp(IBuilderContext context) 
    { 
    if (context.Policies.Get<IMapParameterNameToRegistrationNamePolicy>(context.BuildKey) == null) 
    { 
     return; 
    } 
    IPolicyList resolverPolicyDestination; 
    IConstructorSelectorPolicy selector = context.Policies.Get<IConstructorSelectorPolicy>(context.BuildKey, out resolverPolicyDestination); 
    var selectedConstructor = selector.SelectConstructor(context, resolverPolicyDestination); 
    if (selectedConstructor == null) 
    { 
     return; 
    } 
    var parameters = selectedConstructor.Constructor.GetParameters(); 
    var parameterKeys = selectedConstructor.GetParameterKeys(); 
    for (int i = 0; i < parameters.Length; i++) 
    { 
     Type parameterType = parameters[i].ParameterType; 
     if (parameterType.IsAbstract || parameterType.IsInterface) 
     { 
     IDependencyResolverPolicy resolverPolicy = new NamedTypeDependencyResolverPolicy(parameterType, parameters[i].Name); 
     context.Policies.Set<IDependencyResolverPolicy>(resolverPolicy, parameterKeys[i]); 
     } 
    } 
    resolverPolicyDestination.Set<IConstructorSelectorPolicy>(new SelectedConstructorCache(selectedConstructor), context.BuildKey); 
    } 
} 
public class MapParameterNameToRegistrationName : InjectionMember 
{ 
    public override void AddPolicies(Type serviceType, Type implementationType, string name, IPolicyList policies) 
    { 
    policies.Set<IMapParameterNameToRegistrationNamePolicy>(new MapParameterNameToRegistrationNamePolicy(), new NamedTypeBuildKey(implementationType, name)); 
    } 
} 
public interface IMapParameterNameToRegistrationNamePolicy : IBuilderPolicy 
{ 
} 
public class MapParameterNameToRegistrationNamePolicy : IMapParameterNameToRegistrationNamePolicy 
{ 
} 

代码和测试可以在TecX project on CodePlex的源代码中找到。项目TecX.Unity(文件夹注入)。

1

你为什么不创建一个命令厂

public class CommandFactory (IUnityContainer container) : ICommandFactory 
{ 
    public ICommand CreateSaveCommand() 
    { 
     return container.Resolve("SaveCommand"); 
    } 
    public ICommand CreateLoadCommand() 
    { 
     return container.Resolve("LoadCommand"); 
    } 
} 

public ViewModel(ICommandFactory commandFactory)  
{   
    LoadCommand = commandFactory.CreateLoadCommand();   
    SaveCommand = commandFactory.CreateSaveCommand();   
} 
+0

所以您的解决方案是采取单一行语句'container.RegisterType ( 新InjectionConstructor( 新ResolvedParameter ( “loadCommand”), 新ResolvedParameter ( “SaveCommand”)) );'用完全相同的全新界面和实现替换它?此外,它并没有真正取代那条线,它只是缩短了它。 – cadrell0 2012-07-20 12:38:38

+0

好吧,这取决于你为什么觉得上面的线是“痛苦”? – caa 2012-07-20 14:40:57