как привязать разные TabItems к разным ViewModels

#.net #wpf #mvvm

#.net #wpf #mvvm

Вопрос:

Я не хочу помещать все это в одну ViewModel, я хочу иметь одну ViewModel на TabItem.

Я создал MainViewModel для окна, содержащего TabControl, где у меня есть это свойство currentViewModel, указывающее на значение по умолчанию в конструкторе MainViewModel

     public MainViewModel()
    {
        currentViewModel = "viewModel1";
    }
  

Когда пользователь нажимает на другую TabItem, выполняется

 currentViewModel = "viewModel2";
  

и, конечно, средство доступа set имеет метод OnPropertyChanged

     public String currentViewModel
    {
        get { return _currentViewModel; }

        set
        { 
            _currentViewModel = value;
            OnPropertyChanged("currentViewModel");
        }
    }
  

Еще две ViewModels (ViewModel1, viewModel2), каждая из которых определяет функциональность одной из TabItems, между которыми я хочу переключаться.

Теперь в моем Main.xaml я хочу привязать мой DataContext сначала к MainViewModel, а затем к свойству currentViewModel. чтобы всякий раз, когда пользователь нажимает на TabItem, свойство currentViewModel обновлялось, а DataContext указывал на соответствующую viewmodel.

Комментарии:

1. Используя строку для установки viewmodels? Фу, я не думаю, что это необходимо. Также обычно вокруг этих двух строк в установщике должен быть if (_fieldOfProperty != value) блок.

Ответ №1:

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

В вашем MainWindow будет tabcontrol, и каждый tabitem внутри tabcontrol будет привязан к определенному usercontrol (который обрабатывается как отдельное представление).

mainwindow_View.xaml будет привязан к mainwindow_ViewModel.cs tabItem1_View.xaml будет привязан к ViewModel1.cs tabItem2_View.xaml будет привязан к ViewModel2.cs

Если вам нужен пример кода, дайте мне знать.

Комментарии:

1. Не могли бы вы, пожалуйста, предоставить мне какой-либо пример кода. Заранее спасибо.

Ответ №2:

Я сомневаюсь, что это то, что вы действительно хотите сделать, если у вас разные ViewModels, вы все равно можете привязать свой элемент управления к коллекции этих ViewModels и шаблонировать их по мере необходимости.

Вам просто нужно создать разные DataTemplates на разных уровнях, вот пример (который напрямую использует models, но сейчас это не должно иметь значения):

 <TabControl>
    <TabControl.ItemsSource>
        <!-- This is just sample data, normally you would bind this to an
             ObservableCollection<ViewModelBase> or something similar -->
        <x:Array Type="{x:Type sys:Object}">
            <local:Employee Name="John" Occupation="Programmer"/>
            <local:Employee Name="Steve" Occupation="Coffee Getter"/>
            <local:Machine Manufacturer="iCorp" Model="iMachine"/>
            <local:Machine Manufacturer="iCorp" Model="iMachine G2"/>
            <local:Employee Name="Marc" Occupation="GUI Designer"/>
        </x:Array>
    </TabControl.ItemsSource>
    <TabControl.Resources>
        <!-- These datatemplates define the tab-header appearance, by placing them
             in the TabControl.Resources and setting the DataType they get applied
             automatically, just make one light-weight template for each ViewModel -->
        <DataTemplate DataType="{x:Type local:Employee}">
            <TextBlock>
                <Run Text="{Binding Name}"/>
                <Run Text="("/>
                <Run Text="{Binding Occupation}"/>
                <Run Text=")"/>
            </TextBlock>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:Machine}">
            <TextBlock>
                <Run Text="{Binding Manufacturer}"/>
                <Run Text=" - "/>
                <Run Text="{Binding Model}"/>
            </TextBlock>
        </DataTemplate>

        <ContentControl x:Key="MainContent" Content="{Binding}">
            <ContentControl.Resources>
                <!-- This represents the content of the TabItems, you probably
                     do not need to create DataTemplates but since you could
                     use a View of the ViewModels instead -->
                <DataTemplate DataType="{x:Type local:Employee}">
                    <StackPanel>
                        <TextBlock Text="{Binding Name}"/>
                        <TextBlock Text="{Binding Occupation}"/>
                        <TextBlock Text="{Binding Id}"/>
                        <TextBlock Text="{Binding IsActive}"/>
                    </StackPanel>
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:Machine}">
                    <StackPanel>
                        <TextBlock Text="{Binding Manufacturer}"/>
                        <TextBlock Text="{Binding Model}"/>
                        <TextBlock Text="{Binding VintageYear}"/>
                        <TextBlock Text="{Binding Price}"/>
                    </StackPanel>
                </DataTemplate>
            </ContentControl.Resources>
        </ContentControl>
    </TabControl.Resources>
    <TabControl.ContentTemplate> <!-- Setting the content to the resource -->
        <DataTemplate>
            <Border>
                <StaticResource ResourceKey="MainContent"/>
            </Border>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>
  

Я мог бы попытаться реализовать специфику для MVVM, но, надеюсь, это уже дает представление о том, как к этому можно подойти.

Возможно, вам захочется настроить селектор шаблонов ( TabControl.ContentTemplateSelector ), чтобы получить правильные представления для ваших ViewModels.