私は本当にMVVM、IoC、依存性注入を始めたばかりで、解決方法がわからないというつまずきにぶつかりましたが、なぜそれが起こっているのかは理解しています。
WPFアプリケーションのMVVMフレームワークとして、DIおよびIoC機能にCastle Windsorを使用し、MVVMLightを使用しています。このチュートリアルを使用して、 CastleWindsorにコンストラクターに注入されたを作成させるMainPageViewModel
ことができました。IGroupRepository
CastleWindsorにこれのモック実装を登録しました。
MainPageViewModel
以下は、コンストラクター以外のクラス内の唯一の他のコードです。
public ObservableCollection<GroupViewModel> Groups
{
get
{
var groupVms = new ObservableCollection<GroupViewModel>();
IEnumerable<Group> groups = _repository.GetAllGroups();
foreach (Group g in groups)
{
var vm = new GroupViewModel(g);
groupVms.Add(vm);
}
return groupVms;
}
}
目的は、リポジトリ内のグループごとにビューモデルを作成することです。ただし、これを行うと、CastleWindsorは次の例外を発生させます。
満たすべき依存関係があるため、コンポーネント'Planner.ViewModel.GroupViewModel'を作成できません。'Planner.ViewModel.GroupViewModel'は、次の依存関係を待機しています。
- 登録されていないサービス「Planner.Models.Group」。
私はこの例外を理解しています-CastleWindsorは私のビューモデルを構築する責任がありますが、私のエンティティを処理する方法がありません。
私はグーグルをたくさんしましたが、この問題に対する答えや提案はほとんど見つかりませんでした。それは私がしていることが間違っていると思わせるものです。 このStackOverflowの質問には、ビューモデルにエンティティを含めることは問題ないことを示唆する2つの回答がありますが、それが本当かどうか疑問に思い始めています。このような他の質問は、エンティティがビューモデルの近くにあるべきではないことを示唆しています。
この問題を解決する正しい方法は何ですか?
更新:要求に応じて、これは例外のスタックトレースです。
at Castle.MicroKernel.Handlers.DefaultHandler.AssertNotWaitingForDependency()
at Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, Boolean requiresDecommission, Boolean instanceRequired, Burden& burden)
at Castle.MicroKernel.Handlers.DefaultHandler.Resolve(CreationContext context, Boolean instanceRequired)
at Castle.MicroKernel.Handlers.AbstractHandler.Resolve(CreationContext context)
at Castle.MicroKernel.DefaultKernel.ResolveComponent(IHandler handler, Type service, IDictionary additionalArguments, IReleasePolicy policy)
at Castle.MicroKernel.DefaultKernel.Castle.MicroKernel.IKernelInternal.Resolve(Type service, IDictionary arguments, IReleasePolicy policy)
at Castle.MicroKernel.DefaultKernel.Resolve(Type service, IDictionary arguments)
at Castle.Windsor.WindsorContainer.Resolve(Type service)
at Planner.ViewModel.ViewModelResolver.Resolve(String viewModelName) in D:\Planner\Planner\Planner\ViewModel\ViewModelResolver.cs:line 27
at Planner.ViewModel.ViewModelLocator.get_Item(String viewModelName) in D:\Planner\Planner\Planner\ViewModel\ViewModelLocator.cs:line 21
次のコードがビューモデルのコンストラクターへの呼び出しをインターセプトし、必要に応じてそれらを挿入するため、これは正しい動作だと思いました。
public class ViewModelResolver : IViewModelResolver
{
private IWindsorContainer _container;
public object Resolve(string viewModelName)
{
if (_container == null)
{
_container = new WindsorContainer();
_container.Install(new WindsorViewsInstaller());
_container.Install(new WindsorRepositoriesInstaller());
}
var viewModelType =
GetType()
.Assembly
.GetTypes()
.Where(t => t.Name.Equals(viewModelName))
.FirstOrDefault();
return _container.Resolve(viewModelType);
}
}
更新2:これはリッチの質問に答えると思います:
public class ViewModelLocator : DynamicObject
{
public IViewModelResolver Resolver { get; set; }
public ViewModelLocator()
{
Resolver = new ViewModelResolver();
}
public object this[string viewModelName]
{
get
{
return Resolver.Resolve(viewModelName);
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this[binder.Name];
return true;
}
}
もう少し理解できたと思います。問題は、実際には私が投稿した元のコードにあるのではありません。問題は実際にウィンザーをセットアップすることで発生していますね。しかし、その問題をどのように解決するかはまだわかりません。