2015-04-10 1 views
0

У меня есть UserControlParentView, содержащий DataGrid и catel:TabControl, в котором каждый TabItem крошечное UserControl и чей ViewModel является подкласс BaseTabViewModel.Получить свойство ViewModel TabItem, когда он выбран

Этот BaseTabViewModel содержит ObservableCollection пользовательского класса, свойства которого будут генерировать столбцы DataGrid.

Поскольку у меня есть только один DataGrid для всех вкладок, как я могу автоматически его заполнить с помощью ObservableCollection выбранной модели просмотра tab?

enter image description here

Прямо сейчас, я просто выгружать вкладки (LoadTabItems="SingleUnloadOthers") и, так как ViewModel каждой вкладки регенерировать свою коллекцию, когда инстанциирован, я использую InterestedIn и OnViewModelPropertyChanged, чтобы получить его; но это разгрузочное поведение не является полностью надежным, и я часто оказываюсь с DataGrid, который по-прежнему заполняется предыдущей вкладкой, а не очищается при изменении вкладки.

Следует отметить, что тот факт, что он очищается, не является желательным поведением, у меня просто нет другого выбора прямо сейчас. Каждая загруженная табуляция - моя цель.

Я знаю, что наследование довольно нахмурилось, когда дело доходит до viewmodels, но я, честно говоря, не могу придумать лучшего способа сделать это.


ParentView

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 
    <catel:TabControl LoadTabItems="SingleUnloadOthers"> 
     <TabItem Header="FIRST"> 
      <local:FirstView/> 
     </TabItem> 
     <TabItem Header="SECOND"> 
      <local:SecondView/> 
     </TabItem> 
     <TabItem Header="THIRD"> 
      <local:ThirdView/> 
     </TabItem> 
     <TabItem Header="FOURTH"> 
      <local:FourthView/> 
     </TabItem> 
    </catel:TabControl> 

    <DataGrid Grid.Row="1" IsReadOnly="True" ItemsSource="{Binding Fields}"/> 
</Grid> 

ParentViewModel

[InterestedIn(typeof(FirstViewModel))] 
[InterestedIn(typeof(SecondViewModel))] 
[InterestedIn(typeof(ThirdViewModel))] 
[InterestedIn(typeof(FourthViewModel))] 
public class ParentViewModel : ViewModelBase 
{ 
    public ObservableCollection<Field> Fields 
    { 
     get { return GetValue<ObservableCollection<Field>>(FieldsProperty); } 
     set { SetValue(FieldsProperty, value); } 
    } 
    public static readonly PropertyData FieldsProperty = RegisterProperty("Fields", typeof(ObservableCollection<Field>)); 

    protected override void OnViewModelPropertyChanged(IViewModel viewModel, string propertyName) 
    { 
     if (propertyName.Equals("Fields")) 
     { 
      BaseParserViewModel p = viewModel as BaseParserViewModel; 
      Fields = p != null ?? p.Fields; 
     } 
     base.OnViewModelPropertyChanged(viewModel, propertyName); 
    } 
} 

BaseTabViewModel

public abstract class BaseTabViewModel : ViewModelBase 
{ 
    protected BaseParserViewModel() 
    { 
     Fields = new ObservableCollection<Field>(); 
    } 

    public ObservableCollection<Field> Fields 
    { 
     get { return GetValue<ObservableCollection<Field>>(FieldsProperty); } 
     set { SetValue(FieldsProperty, value); } 

    public static readonly PropertyData FieldsProperty = RegisterProperty("Fields", typeof(ObservableCollection<MappedField>)); 

} 

У детей BaseTabViewModel нет ничего интересного, так как они не взаимодействуют со своим родителем, за исключением некоторых свойств [ViewModelToModel].

ответ

1

Если вам нужно управлять состоянием на нескольких моделях просмотра, я всегда рекомендую ввести услугу. Модель просмотра - это то, что может жить в течение короткого или длительного промежутка времени, но наилучшая связь между моделями просмотров - это все еще службы, которые удерживают состояние (даже когда vm исчезли).

Ниже мои предпочтения сообщения:

  1. Услуги (лучший способ, позволяет полный контроль, лучшее исполнение)
  2. Атрибут связи на основе
  3. сообщений (MessageMediator)

Я знаю, многие люди исправляют свои архитектурные проблемы с 3, но это взломать, а не твердое решение.Просто реализовать услугу (которая получает впрыскивается во все ВМ), как это:

public class FieldCollectionManagementService : IFieldCollectionManagementService 
{ 
    private ObservableCollection<Field> _selectedCollection; 

    public ObservableCollection<Field> SelectedCollection 
    { 
     get { return _selectedCollection; } 
     set 
     { 
      _selectedCollection = value; 
      SelectedCollectionChanged.SafeInvoke(this); 
     } 
    } 

    public event EventHandler<EventArgs> SelectedCollectionChanged; 
} 

Теперь вы можете легко обрабатывать все изменения без необходимости атрибутов. Тогда вы можете даже восстановить состояние, когда все модели просмотра исчезли.

+0

Ничего себе. Наверное, я устал не думать об этом. Тем не менее я не знаю, как я могу определить модель просмотра для ребенка, которая была выбрана ... Но я на самом деле пытаюсь что-то сделать так, чтобы дети BaseTabViewModel находились в свойстве коллекции внутри ParentViewModel и динамически создавали TabItems из этой коллекции ... Я полагаю, что это вложенные viewmodels. – Kilazur

+0

Если вы используете поведение вкладок «UnloadOthers», вы можете изменить выбор в методе Initialize моделей просмотра. –

+1

Я согласен с вашим ответом, но это не соответствует моей проблеме. У меня довольно сложная система унаследованных классов, и я решил решить несколько вложенных режимов просмотра. Он чище и проще в обслуживании и отладке, вместо того, чтобы следить за связью OnViewModelPropertyChanged и позволяет мне динамически создавать представления (благодаря ViewModelToModelConverter). – Kilazur