2012-07-19 2 views
2

ICommand을 내 ViewModel에 삽입하는 올바른 방법을 알아 내려고하고 있습니다.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; 
} 

IBar

를 주입하는 것이 더 적절할 것이다하지만 지금은 Bar1Bar2 있습니다. 그래서

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

또는

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

를 작성 해달라고? 뷰 모델의 한 가지 목적은 뷰 로직을 노출하는 것입니다. 메세지 박스 서비스 나 그런 것들을 주입하고 싶다면 - 나는 너와 함께하지만 명령은 뷰 모델에 속한다. 또는이 명령을 어떤 방식 으로든 다시 사용 하시겠습니까? – blindmeis

+0

@blindmeis 일부 명령은 재사용 할 수 있습니다.하지만 그것이 내 질문의 요점이다. 명령에 매개 변수를 전달하는 매개 변수를 주입하는 경우 명령을 주입해야합니까? – cadrell0

+3

예 최대한의 유연성을 유지하려면 매개 변수 대신 명령에 전달해야합니다. 예를 들어 명령을 전달하면 테스트를 위해 Command 객체를 모의 할 수 있습니다. 더 많은 명령을 전달하면 앞으로 명령을 다르게 빌드 할 수 있습니다. 예를 들어 각 명령이 다른 오류 로그에 기록하도록 허용합니다. 각 객체는 자체 매개 변수를 가져 와서 객체 그래프를 작성해야합니다. params를 뷰 모델로 전달하면 어떤 이점이 있습니까? – caa

답변

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 (폴더 주입). 당신이 모든에 ICommand의를 주입하려는 이유

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

+0

글쎄, 왜 위 라인이 "고통"이라고 느껴지 느냐? – caa