彩票走势图

logo DevExpress WinForm中文手册

视图模型管理


立即下载DevExpress WinForms

本文描述了如何在运行时检索ViewModel实例,注意如果您在设计时使用MvvmContext组件来构建 MVVM-applications,该组件将自动管理ViewModels。

如果ViewModel遵循POCO概念,MVVM框架将动态地把该ViewModel转换为包含必要基础结构(例如,支持简化的)的新类。框架与动态创建的类实例一起工作,这意味着您无法在运行时初始访问这些实例,因为它们的类型尚未确定。

使用以下选项来检索工作的ViewMode:

  • The ViewModelSource.Create method

在这种方法中,您首先创建一个ViewModel实例,然后调用SetViewModel方法将该实例与特定的ViewModel类型关联起来。

C#:

var mainViewModel = ViewModelSource.Create<MainViewModel>();
mvvmContext1.SetViewModel(typeof(MainViewModel), mainViewModel);

VB.NET:

Dim mainViewModel = ViewModelSource.Create(Of MainViewModel)()
mvvmContext1.SetViewModel(GetType(MainViewModel), mainViewModel)
  • The ViewModelBase class

您可以从实现MVVM框架特性的ViewModelBase类中继承ViewModels,在这种情况下,是可以直接创建ViewModel实例。注意,此时还需调用SetViewModel方法来指定框架在需要ViewModel时应该使用这个实例。

C#:

public class ViewModel : ViewModelBase {
//. . .
}
var myViewModel = new ViewModel();
mvvmContext1.SetViewModel(typeof(ViewModel), myViewModel);

VB.NET:

Public Class ViewModel
Inherits ViewModelBase

'. . .
End Class
Private myViewModel = New ViewModel()
mvvmContext1.SetViewModel(GetType(ViewModel), myViewModel)

我们不推荐这种方法,因为您将失去POCO模型提供的所有特性。

  • ViewModelCreate events

这种方法被设计为与依赖注入框架(如)一起工作,下面的例子说明了这种注入是如何与Ninject 框架一起工作的。

C#:

public class SamuraiViewModel {
public IWeapon Weapon { get; private set; }
public SamuraiViewModel(IWeapon weapon) {
this.Weapon = weapon;
}
public void Attack() {
Weapon.Hit();
}
}

// Bind a dependency for IWeapon
kernel.Bind<IWeapon>().To<Sword>();

// Set up MVVMContext
var fluent = mvvmContext1.OfType<SamuraiViewModel>();
fluent.BindCommand(simpleButton1, x => x.Attack());

VB.NET:

Public Class SamuraiViewModel
Private privateWeapon As IWeapon
Public Property Weapon() As IWeapon
Get
Return privateWeapon
End Get
Private Set(ByVal value As IWeapon)
privateWeapon = value
End Set
End Property
Public Sub New(ByVal weapon As IWeapon)
Me.Weapon = weapon
End Sub
Public Sub Attack()
Weapon.Hit()
End Sub
End Class

' Bind a dependency for IWeapon
kernel.Bind(Of IWeapon)().To(Of Sword)()

' Set up MVVMContext
Dim fluent = mvvmContext1.OfType(Of SamuraiViewModel)()
fluent.BindCommand(simpleButton1, Function(x) x.Attack())

在这种情况下,您需要动态生成Viewmodel并将它们绑定到接口(当将接口直接绑定到POCO时,MVVM框架特性将丢失)。要获得所需的实例,处理常规(本地)或静态(全局)ViewModelCreate事件如下:

C#:

// Retrieve the live POCO ViewModel instance with the Ninject kernel
//regular event
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);
}
//static event
MVVMContextCompositionRoot.ViewModelCreate += (s,e)=> {
e.ViewModel = kernel.Get(e.RuntimeViewModelType);
};

VB.NET:

' Retrieve the live POCO ViewModel instance with the Ninject kernel
'regular event
AddHandler mvvmContext1.ViewModelCreate, AddressOf 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)
'static event
AddHandler MVVMContextCompositionRoot.ViewModelCreate, Sub(s,e) e.ViewModel = kernel.Get(e.RuntimeViewModelType)

静态ViewModelCreate事件是一个weak event,如果它包含一个变量的闭包(上面示例中的" kernel "或下面示例中的" rootContainer "范围),其生命周期短于父容器的生命周期,那么VS垃圾收集器可能会过早地收集该变量,并且事件处理程序可能永远不会被调用。

C#:

[STAThread]
static void Main() {
//rootContainer is declared at the Main method level
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);
}
};
}

VB.NET:

<STAThread>
Shared Sub Main()
'rootContainer is declared at the Main method level
Dim rootContainer As IContainer
Dim builder = New ContainerBuilder()
builder.RegisterType(Of TestViewModel)()
builder.RegisterType(Of [MyClass])().As(Of IService)()
rootContainer = builder.Build()
AddHandler MVVMContextCompositionRoot.ViewModelCreate, Sub(s, e)
Using scope = rootContainer.BeginLifetimeScope(Function(b) b.RegisterType(e.RuntimeViewModelType).As(e.ViewModelType))
e.ViewModel = scope.Resolve(e.ViewModelType)
End Using
End Sub
End Sub

要解决潜在的问题,请在执行订阅的对象级别将变量声明为属性/字段。

C#:

//rootContainer is declared at the root level
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);
}
};
}

VB.NET:

'rootContainer is declared at the root level
Private Shared Property rootContainer() As IContainer
<STAThread>
Shared Sub Main()
Dim builder = New ContainerBuilder()
builder.RegisterType(Of TestViewModel)()
builder.RegisterType(Of [MyClass])().As(Of IService)()
rootContainer = builder.Build()
AddHandler MVVMContextCompositionRoot.ViewModelCreate, Sub(s, e)
Using scope = rootContainer.BeginLifetimeScope(Function(b) b.RegisterType(e.RuntimeViewModelType).As(e.ViewModelType))
e.ViewModel = scope.Resolve(e.ViewModelType)
End Using
End Sub
End Sub
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP