在 WPF/CaliburnMicro/AutoFac 中创建通用 ViewModelFactory
Create a generic ViewModelFactory in WPF/CaliburnMicro/AutoFac
我有一个使用 Caliburn.Micro 和 AutoFac
的 WPF 应用程序
在 Bootstrapper.Configure() 中,我将我的视图和视图模型注册为:
protected override void Configure()
{
var builder = new ContainerBuilder();
// register view models
builder.RegisterAssemblyTypes(AssemblySource.Instance.ToArray())
.Where(type => type.Name.EndsWith("ViewModel"))
.AsSelf()
.InstancePerDependency();
// register views
builder.RegisterAssemblyTypes(AssemblySource.Instance.ToArray())
.Where(type => type.Name.EndsWith("View"))
.AsSelf()
.InstancePerDependency();
builder.Register<IWindowManager>(c => new WindowManager()).InstancePerLifetimeScope();
_container = builder.Build();
}
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[]
{
typeof (MainViewModel).Assembly, // assembly that holds all the ViewModels
typeof (MainView).Assembly // assembly that holds all the Views
};
}
这很好用,视图和视图模型很好地按照此约定映射,例如。实例化 RandomViewModel 时,会显示 RandomView。
此外,我有很多 edit/list 派生自通用基础 类 的视图模型,其中通用类型是我解决方案中的实体。
例如,当我有实体 UserEntity、OrderEntity、AccountEntity 等时...
然后我会创建 类:
//base classes
abstract class EditViewModelBase<T> : IEditViewModelBase where T: IEntity
abstract class ListViewModelBase<T> : IListViewModelBase where T: IEntity
//implementations
class UserEditViewModel : EditViewModelBase<UserEntity> {...}
class OrderEditViewModel : EditViewModelBase<OrderEntity> {...}
class AccountEditViewModel : EditViewModelBase<AccountEntity> {...}
...
class UserListViewModel : ListViewModelBase<UserEntity> {...}
class OrderListViewModel : ListViewModelBase<OrderEntity> {...}
class UserListViewModel : ListViewModelBase<UserEntity> {...}
...
现在我想创建一个 ViewModelFactory 以通用方式定位视图模型:
class ViewModelFactory
{
public IEditViewModelBase CreateEditViewModel<T>()
{
//this method should do :
// if typeof(T) == typeof(UserEntity) return new UserEditViewModel();
// if typeof(T) == typeof(OrderEntity) return new OrderEditViewModel();
// if typeof(T) == typeof(UserEntity) return new UserEditViewModel();
...
}
public IListViewModelBase CreateListViewModel<T>()
{
//this method should do :
// if typeof(T) == typeof(OrderEntity) return new OrderListViewModel();
...
}
}
我该如何解决这个问题,这样我就不必在每次向我的解决方案中添加新实体和 ViewModel 时都更改 ViewModelFactory?
我正在考虑循环遍历容器,使用像 IsInstanceOf 和 Activator.CreateInstance 这样的反射技巧,但我无法让它工作...
我认为最简单的方法是使用内部使用 AutoFac 的 Auto Factory 库。
你可以这样解决:
using AutoFactory;
class ViewModelFactory
{
private IAutoFactory<IEditViewModelBase> _editFactory = Factory.Create<IEditViewModelBase>();
private IAutoFactory<IListViewModelBase> _listFactory = Factory.Create<IListViewModelBase>();
public IEditViewModelBase CreateEditViewModel<T>()
{
return _editFactory.SeekPart(t => t.BaseType.GetGenericArguments()[0].Name == typeof(T).Name);
}
public IListViewModelBase CreateListViewModel<T>()
{
return _listFactory.SeekPart(t => t.BaseType.GetGenericArguments()[0].Name == typeof(T).Name);
}
}
或者如果你想直接用 AutoFac 做,你可以这样做:
using Autofac.Builder;
using Autofac.Features.Metadata
class ViewModelFactory
{
private IContainer _container;
private IEnumerable<Meta<Lazy<IEditViewModelBase>>> _editParts;
public ViewModelFactory()
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(this.GetType().Assembly)
.Where(t => typeof(IEditViewModelBase).IsAssignableFrom(t))
.As<IEditViewModelBase>()
.WithMetadata("type", t => t.BaseType.GetGenericArguments()[0]);
_container = builder.Build();
_editParts = _container.Resolve<IEnumerable<Meta<Lazy<IEditViewModelBase>>>>();
}
public IEditViewModelBase CreateEditViewModel<T>()
{
return _editParts.FirstOrDefault(p => p.Metadata["type"] as Type == typeof(T)).Value.Value;
}
...
}
我觉得
public class Bootstrapper
{
public IContainer Bootstrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<EventAggregator>().As<IEventAggregator>().SingleInstance();
builder.RegisterType<MessageDialogService>().As<IMessageDialogService>();
builder.RegisterType<FileDataService>().As<IDataService>();
builder.RegisterType<fLookupProvider>().As<ILookupProvider<f>>();
builder.RegisterType<fGroupLookupProvider>().As<ILookupProvider<fGroup>>();
builder.RegisterType<fDataProvider>().As<IfDataProvider>();
builder.RegisterType<fEditViewModel>().As<IfEditViewModel>();
builder.RegisterType<NavigationViewModel>().As<INavigationViewModel>();
builder.RegisterType<MainViewModel>().AsSelf();
return builder.Build();
}
}
我有一个使用 Caliburn.Micro 和 AutoFac
的 WPF 应用程序在 Bootstrapper.Configure() 中,我将我的视图和视图模型注册为:
protected override void Configure()
{
var builder = new ContainerBuilder();
// register view models
builder.RegisterAssemblyTypes(AssemblySource.Instance.ToArray())
.Where(type => type.Name.EndsWith("ViewModel"))
.AsSelf()
.InstancePerDependency();
// register views
builder.RegisterAssemblyTypes(AssemblySource.Instance.ToArray())
.Where(type => type.Name.EndsWith("View"))
.AsSelf()
.InstancePerDependency();
builder.Register<IWindowManager>(c => new WindowManager()).InstancePerLifetimeScope();
_container = builder.Build();
}
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[]
{
typeof (MainViewModel).Assembly, // assembly that holds all the ViewModels
typeof (MainView).Assembly // assembly that holds all the Views
};
}
这很好用,视图和视图模型很好地按照此约定映射,例如。实例化 RandomViewModel 时,会显示 RandomView。
此外,我有很多 edit/list 派生自通用基础 类 的视图模型,其中通用类型是我解决方案中的实体。
例如,当我有实体 UserEntity、OrderEntity、AccountEntity 等时... 然后我会创建 类:
//base classes
abstract class EditViewModelBase<T> : IEditViewModelBase where T: IEntity
abstract class ListViewModelBase<T> : IListViewModelBase where T: IEntity
//implementations
class UserEditViewModel : EditViewModelBase<UserEntity> {...}
class OrderEditViewModel : EditViewModelBase<OrderEntity> {...}
class AccountEditViewModel : EditViewModelBase<AccountEntity> {...}
...
class UserListViewModel : ListViewModelBase<UserEntity> {...}
class OrderListViewModel : ListViewModelBase<OrderEntity> {...}
class UserListViewModel : ListViewModelBase<UserEntity> {...}
...
现在我想创建一个 ViewModelFactory 以通用方式定位视图模型:
class ViewModelFactory
{
public IEditViewModelBase CreateEditViewModel<T>()
{
//this method should do :
// if typeof(T) == typeof(UserEntity) return new UserEditViewModel();
// if typeof(T) == typeof(OrderEntity) return new OrderEditViewModel();
// if typeof(T) == typeof(UserEntity) return new UserEditViewModel();
...
}
public IListViewModelBase CreateListViewModel<T>()
{
//this method should do :
// if typeof(T) == typeof(OrderEntity) return new OrderListViewModel();
...
}
}
我该如何解决这个问题,这样我就不必在每次向我的解决方案中添加新实体和 ViewModel 时都更改 ViewModelFactory? 我正在考虑循环遍历容器,使用像 IsInstanceOf 和 Activator.CreateInstance 这样的反射技巧,但我无法让它工作...
我认为最简单的方法是使用内部使用 AutoFac 的 Auto Factory 库。 你可以这样解决:
using AutoFactory;
class ViewModelFactory
{
private IAutoFactory<IEditViewModelBase> _editFactory = Factory.Create<IEditViewModelBase>();
private IAutoFactory<IListViewModelBase> _listFactory = Factory.Create<IListViewModelBase>();
public IEditViewModelBase CreateEditViewModel<T>()
{
return _editFactory.SeekPart(t => t.BaseType.GetGenericArguments()[0].Name == typeof(T).Name);
}
public IListViewModelBase CreateListViewModel<T>()
{
return _listFactory.SeekPart(t => t.BaseType.GetGenericArguments()[0].Name == typeof(T).Name);
}
}
或者如果你想直接用 AutoFac 做,你可以这样做:
using Autofac.Builder;
using Autofac.Features.Metadata
class ViewModelFactory
{
private IContainer _container;
private IEnumerable<Meta<Lazy<IEditViewModelBase>>> _editParts;
public ViewModelFactory()
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(this.GetType().Assembly)
.Where(t => typeof(IEditViewModelBase).IsAssignableFrom(t))
.As<IEditViewModelBase>()
.WithMetadata("type", t => t.BaseType.GetGenericArguments()[0]);
_container = builder.Build();
_editParts = _container.Resolve<IEnumerable<Meta<Lazy<IEditViewModelBase>>>>();
}
public IEditViewModelBase CreateEditViewModel<T>()
{
return _editParts.FirstOrDefault(p => p.Metadata["type"] as Type == typeof(T)).Value.Value;
}
...
}
我觉得
public class Bootstrapper
{
public IContainer Bootstrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<EventAggregator>().As<IEventAggregator>().SingleInstance();
builder.RegisterType<MessageDialogService>().As<IMessageDialogService>();
builder.RegisterType<FileDataService>().As<IDataService>();
builder.RegisterType<fLookupProvider>().As<ILookupProvider<f>>();
builder.RegisterType<fGroupLookupProvider>().As<ILookupProvider<fGroup>>();
builder.RegisterType<fDataProvider>().As<IfDataProvider>();
builder.RegisterType<fEditViewModel>().As<IfEditViewModel>();
builder.RegisterType<NavigationViewModel>().As<INavigationViewModel>();
builder.RegisterType<MainViewModel>().AsSelf();
return builder.Build();
}
}