本文描述了如何在运行时取出ViewModel实例。注意,如果在设计时使用MvvmContext组件来构建MVVM化的应用程序,该组件将自动管理视图模型。
如果ViewModel遵循POCO原则,那么MVVM框架会动态地将这个ViewModel转换为包含必要基础设施(例如,支持简化的数据绑定)的新类。框架使用动态创建的类实例,这意味着您不能在运行时初始化访问这些实例,因为它们的类型还没有确定。
请使用下面的选项来取出运行时的ViewModel:
- ViewModelSource.Create 方法
在这种方法中,您首先创建一个ViewModel实例,然后调用SetViewModel方法将该实例与特定的ViewModel类型关联起来。var mainViewModel = ViewModelSource.Create<MainViewModel>(); mvvmContext1.SetViewModel(typeof(MainViewModel), mainViewModel);
- ViewModelBase类
您可以创建一个ViewModel,它须继承自实现了MVVM框架特性的ViewModelBase类。在这种情况下,您可以直接创建ViewModel实例。但请注意,您还需要调用SetViewModel方法来指定框架在需要ViewModel时应该使用这个实例。
我们不建议使用这种方法,因为这样会丢失POCO模型所提供的所有特性。public class ViewModel : ViewModelBase { //. . . } var myViewModel = new ViewModel(); mvvmContext1.SetViewModel(typeof(ViewModel), myViewModel);
- ViewModelCreate事件
这种方法被设计用于依赖注入框架(如Ninject)。下面的示例说明了这种注入方式,是如何与Ninject框架一起工作的。
在这个场景中,您需要动态生成视图模型并将它们绑定到接口(当直接将接口绑定到POCO时,MVVM框架特性将丢失)。要获得所需的实例,处理常规(本地)或静态(全局)ViewModelCreate事件如下:public class SamuraiViewModel { public IWeapon Weapon { get; private set; } public SamuraiViewModel(IWeapon weapon) { this.Weapon = weapon; } public void Attack() { Weapon.Hit(); } } // 为IWeapon绑定一个依赖 kernel.Bind<IWeapon>().To<Sword>(); // 装配MVVMContext var fluent = mvvmContext1.OfType<SamuraiViewModel>(); fluent.BindCommand(simpleButton1, x => x.Attack());
静态ViewModelCreate事件是一个弱事件。如果它包含一个对一个变量(上面示例中的“kernel”或下面Autofac示例中的“rootContainer”作用域)的闭包,其生存期比父容器的生存期短,则VS垃圾收集器可以提前收集这个变量,并且事件处理程序可能永远不会被调用。// 使用Ninject内核取出存活的POCO ViewModel实例 //常规事件 mvvmContext1.ViewModelCreate += MVVMContext_ViewModelCreate; void MVVMContext_ViewModelCreate(object sender, DevExpress.Utils.MVVM.ViewModelCreateEventArgs e) { // kernel.Bind<SamuraiViewModel>().To(e.RuntimeViewModelType); // e.ViewModel = kernel.Get<SamuraiViewModel>(); e.ViewModel = kernel.Get(e.RuntimeViewModelType); } //静态事件 MVVMContextCompositionRoot.ViewModelCreate += (s,e)=> { e.ViewModel = kernel.Get(e.RuntimeViewModelType); };
要解决这个潜在问题,可以在执行订阅的对象的级别上,将变量声明为属性/字段。[STAThread] static void Main() { //rootContainer被声明在Main方法级上 IContainer rootContainer; var builder = new ContainerBuilder(); builder.RegisterType<TestViewModel>(); builder.RegisterType<MyClass>().As<IService>(); rootContainer = builder.Build(); MVVMContextCompositionRoot.ViewModelCreate += (s, e) => { using (var scope = rootContainer.BeginLifetimeScope( b => b.RegisterType(e.RuntimeViewModelType).As(e.ViewModelType))) { e.ViewModel = scope.Resolve(e.ViewModelType); } }; }
//rootContainer被声明在root级别上 private static IContainer rootContainer { get; set; } [STAThread] static void Main() { var builder = new ContainerBuilder(); builder.RegisterType<TestViewModel>(); builder.RegisterType<MyClass>().As<IService>(); rootContainer = builder.Build(); MVVMContextCompositionRoot.ViewModelCreate += (s, e) => { using (var scope = rootContainer.BeginLifetimeScope( b => b.RegisterType(e.RuntimeViewModelType).As(e.ViewModelType))) { e.ViewModel = scope.Resolve(e.ViewModelType); } }; }