用另一个ViewModel替换View的ViewModel

时间:2012-04-19 09:30:56

标签: wpf prism mef

我有两个应用程序,一个是主应用程序,另一个是设计器表单应用程序。

目前,我的主要应用程序正在使用prism和mef。我的主要应用程序中的一些视图只是数据输入表单。我想从我的设计器表单应用程序中加载一个数据输入表单视图,然后可以对其进行编辑,但为了做到这一点,我想使用不同的viewmodel进行设计。我不希望表单附加到它通常的viewmodel并尝试获取数据等。

如何使用MEF我能够提供一个不同的导出,以便它选择这个而不是通常的viewmodel?理想情况下,它只是替换主应用程序视图模型,因此它只是使用它。

这是我的示例视图,导入viewmodel

[Export("PatientDetailView")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class PatientDetailView : UserControl
{
    [ImportingConstructor]
    public PatientDetailView(PatientDetailViewModel viewModel)
    {
        InitializeComponent();

        this.DataContext = viewModel;
    }
}

这是我的viewmodel的基础:

[Export(typeof(PatientDetailViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class PatientDetailViewModel : ViewModelBase, IRegionManagerAware
{
    [ImportingConstructor]
    public PatientDetailViewModel(IEventAggregator eventAggregator, IDialogService dialogService, IRegionManager regionManager)
        : base(eventAggregator, dialogService, regionManager)
    {
       //Contains Commands etc for Saving Patient Detail Record
       //Receiving patient detail etc 
    }

}

更新

以上内容包含在患者模块组件中。这适用于主应用程序的应用方式。对于Designer应用程序,我想用以下内容替换上面的视图模型:

[Export(typeof(PatientDetailViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class PatientDetailViewModel : ViewModelBase, IRegionManagerAware
{
    [ImportingConstructor]
    public PatientDetailViewModel(IEventAggregator eventAggregator, IDialogService dialogService, IRegionManager regionManager)
        : base(eventAggregator, dialogService, regionManager)
    {
       //Contains Commands etc for Designing the form
       //No commands from the original VM so changes how it tries to work.
    }

}

以上是为了覆盖主应用程序的默认行为。此VM将包含在Designer程序集或单独的designerVMs程序集中。

2 个答案:

答案 0 :(得分:0)

因为这些是单独的应用程序,而datacontext可以是任何对象,所以解决方案可以很简单。

视图已更改为按名称导入其datacontext。

public static class MefContracts
{
  public const string PatientDetailViewModel = "PatientDetailViewModel";
}

[Export("PatientDetailView")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class PatientDetailView : UserControl, IPartImportsSatisfiedNotification
{
  [Import( MefContracts.PatientDetailViewModel, typeof( object )]
  private object vm;

  public void OnImportsSatisfied()
  {
    this.DataContext = vm;
  }


  public PatientDetailView()
  {
    InitializeComponent();
  }
}

然后,根据应用程序,您只包含所需的ViewModel并按名称

导出
[Export( MefContracts.PatientDetailViewModel, typeof( object ) ) )]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class PatientDetailViewModel : ViewModelBase, IRegionManagerAware
{
  ....
}

更新如果你真的无法分离程序集(这仍然是最好的选择,在不同的程序集中使用vm没有任何问题),你可以使用简单的工厂代替(到抽象获取ViewModel的方式):导入可以创建vm的工厂,而不是导入vm。它创建的是一个配置值,必须在每个应用程序中设置不同。您必须使用不同的合同导出vms,否则没有(简单)方法来区分它们。例如:

public static class MefContracts
{
  public const string PatientDetailViewModelMain = "PatientDetailViewModelMain";
  public const string PatientDetailViewModelDesigner = "PatientDetailViewModelDesigner";
}

//the main vm
[Export( MefContracts.PatientDetailViewModelMain, typeof( object ) ) )]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class PatientDetailViewModel : ViewModelBase, IRegionManagerAware
{
  ....
}

//the other vm
[Export( MefContracts.PatientDetailViewModelDesigner, typeof( object ) ) )]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class OtherPatientDetailViewModel : ViewModelBase, IRegionManagerAware
{
  ....
}

[Export("PatientDetailView")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class PatientDetailView : UserControl
{
  [ImportingConstructor]
  public PatientDetailView( PatientDetailViewModelFactory viewModelFactory )
  {
    InitializeComponent();
    this.DataContext = viewModelFactory.Create();
  }
}

[Export]
class PatientDetailViewModelFactory
{
  [Import]
  private CompositionContainer container{ get; set; }

  public enum AppType{ Main, Designer }

  public AppType AppType{ get; set; }

  public object Create()
  {
    return container.GetExportedValue<object>( 
      AppType == AppType.Main ? MefContracts.PatientDetailViewModelMain :
                                MefContracts.PatientDetailViewModelDesigner );
  }
}

答案 1 :(得分:0)

尝试这样的事情:

创建一个定义视图模型的界面:

public interface IPatientDetailViewModel{...}

在主应用程序中,从界面派生您的视图模型并修改Export属性。

[Export(typeof(IPatientDetailViewModel)]
public class PatientDetailViewModel : ViewModelBase, 
    IRegionManagerAware, IPatientViewModel
{ ... }

我假设视图位于共享程序集中。在视图中添加默认构造函数(如果未在设计应用程序中使用Mef),并更改导入以使用界面:

public PatientDetailView()
{
    InitializeComponent();
}

[ImportingConstructor]
public PatientDetailView(IPatientDetailViewModel viewModel)
{
    InitializeComponent();

    this.DataContext = viewModel;
}

现在,如果您的设计器应用使用MEF,则可以导出要导入到视图中的其他视图模型

[Export(typeof(IPatientDetailViewModel)]
public class DesignPatientDetailViewModel : ViewModelBase, IPatientViewModel
{ ... }

或者如果不使用MEF使用

d:DataContext="{d:DesignInstance local:DesignPatientViewModel}" 

在你视图中的Xaml。