【发布时间】:2012-07-18 18:38:20
【问题描述】:
我真的刚刚开始使用 MVVM、IoC 和依赖注入,我遇到了一个我不知道如何解决的绊脚石,但我明白为什么会这样。
我在 WPF 应用程序中将 Castle Windsor 用于 DI 和 IoC 功能,并将 MVVM Light 作为我的 MVVM 框架。使用this tutorial,我设法让Castle Windsor 创建一个MainPageViewModel,将IGroupRepository 注入到构造函数中。我已经在温莎城堡注册了一个模拟实现。
以下是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;
}
}
目的是为存储库中的每个组创建一个视图模型。但是,这样做会导致 Castle Windsor 给出以下异常:
无法创建组件“Planner.ViewModel.GroupViewModel”,因为它具有依赖项 要满足。 'Planner.ViewModel.GroupViewModel' 正在等待以下依赖项:
- 未注册的服务“Planner.Models.Group”。
我了解此异常 - Castle Windsor 负责构建我的视图模型,但它无法处理我的实体。
我在谷歌上搜索了很多,但对这个问题的答案或建议却很少,这让我认为我所做的事情是错误的。 This Stack Overflow question 有两个答案表明在视图模型上有一个实体是可以的,但我开始怀疑这是不是真的。其他问题,such as this one 建议实体不应靠近视图模型。
解决这个问题的正确方法是什么?
更新:根据要求,这是异常的堆栈跟踪:
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:我认为这回答了 Ritch 的疑问:
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;
}
}
我想我现在更了解这一点了。问题实际上不在于我发布的原始代码。问题实际上是在设置温莎时发生的,不是吗?不过,我仍然不确定如何解决这个问题。
【问题讨论】:
-
通读您的示例,我看不出您在哪里要求 Castle Windsor 创建 GroupViewModel。在示例代码中,您直接调用构造函数,这不会涉及 Castle Windsor。你能显示异常的堆栈跟踪吗?
-
容器如何绑定到您正在创建的 GroupViewModels?
-
@RitchMelton 我已经用我认为可以回答您问题的代码更新了问题。我还用我的一些新见解对其进行了更新。
标签: c# mvvm dependency-injection inversion-of-control castle-windsor