2012-04-19 2 views
1

У меня есть два приложения, одно из которых - основное приложение, а другое - приложение формы дизайнера.Заменить 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 
    } 

}

UPDATE:

выше содержится в модуле пациента сборка. Это работает как для основного приложения. Для применения конструктора я хочу заменить вышеупомянутую модель представления что-то вроде ниже:

[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. 
    } 

}

выше работает переопределить поведение по умолчанию для моего основного приложения. Эта виртуальная машина будет содержаться в сборке конструктора или отдельной сборке designerVM.

ответ

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 
{ 
    .... 
} 

обновление если вы действительно не можете Seperate сборки (что имо еще лучший вариант, там нет ничего плохого в том, что 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); 
    } 
} 
+0

Хорошо, спасибо за ответы. Моя проблема в том, что я не знаю, как включить только ViewModel, который я хочу. Поскольку основная виртуальная машина приложения всегда экспортируется, когда я включаю сборку с моим представлением. Я могу экспортировать свою другую виртуальную машину в моем приложении Designer, но затем есть два экспорта, можно ли заменить этот экспорт на новый? –

+0

Не можете ли вы поместить каждый vm в отдельную сборку и включить только одну из этих сборок для каждого приложения? – stijn

+0

Не совсем, ViewModel должен идти с View в той же сборке, никогда не видел их в другом месте. Это часть этого модуля, может показаться немного неправильной в другой сборке только для целей дизайнера. Я думал, что MEF все касается компонентов горячей замены. –

0

попробовать что-то вроде этого:

Создайте интерфейс, который определяет модель вида:

public interface IPatientDetailViewModel{...} 

В вас главное приложение вывести вашу модель представления из интерфейса и изменить атрибут экспорта ,

[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 вашего вида.

Смежные вопросы