Как привязать элемент управления TabControl к коллекции ViewModels?


в основном у меня есть в моем MainViewModel.cs:

ObservableCollection<TabItem> MyTabs { get; private set; }

тем не менее, мне нужно каким-то образом иметь возможность не только создавать вкладки, но и загружать содержимое вкладок и связывать их с соответствующими viewmodels при сохранении MVVM.

в принципе, как я могу получить элемент управления UserControl, который будет загружен как содержание tabitem В и пользовательских элементов управления подключен к соответствующей модели представления. Часть, которая делает это трудным, - это ViewModel, который не должен строить фактические элементы просмотра, верно? Или это возможно?

в принципе, это было бы MVVM уместно:

UserControl address = new AddressControl();
NotificationObject vm = new AddressViewModel();
address.DataContext = vm;
MyTabs[0] = new TabItem()
{
    Content = address;
}

Я только спрашиваю, потому что хорошо, я строю представление (AddressControl) из ViewModel, который для меня звучит как MVVM no-no.

3 53

3 ответа:

Это не MVVM. Не следует создавать элементы пользовательского интерфейса в модели представления.

вы должны привязать ItemsSource вкладки к вашей ObservableCollection, и это должно содержать модели с информацией о вкладках, которые должны быть созданы.

вот виртуальная машина и модель, которая представляет собой вкладку:

public sealed class ViewModel
{
    public ObservableCollection<TabItem> Tabs {get;set;}
    public ViewModel()
    {
        Tabs = new ObservableCollection<TabItem>();
        Tabs.Add(new TabItem { Header = "One", Content = "One's content" });
        Tabs.Add(new TabItem { Header = "Two", Content = "Two's content" });
    }
}
public sealed class TabItem
{
    public string Header { get; set; }
    public string Content { get; set; }
}

а вот как выглядят привязки в окне:

<Window x:Class="WpfApplication12.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <ViewModel
            xmlns="clr-namespace:WpfApplication12" />
    </Window.DataContext>
    <TabControl
        ItemsSource="{Binding Tabs}">
        <TabControl.ItemTemplate>
            <!-- this is the header template-->
            <DataTemplate>
                <TextBlock
                    Text="{Binding Header}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <!-- this is the body of the TabItem template-->
            <DataTemplate>
                <TextBlock
                    Text="{Binding Content}" />
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</Window>

(обратите внимание, если вы хотите разные вещи различные вкладки, используйте DataTemplates. Либо модель представления каждой вкладки должна быть собственным классом, либо создать пользовательский DataTemplateSelector чтобы выбрать правильный шаблон.)

О, смотрите, UserControl внутри шаблона данных:

<TabControl
    ItemsSource="{Binding Tabs}">
    <TabControl.ItemTemplate>
        <!-- this is the header template-->
        <DataTemplate>
            <TextBlock
                Text="{Binding Header}" />
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <!-- this is the body of the TabItem template-->
        <DataTemplate>
            <MyUserControl xmlns="clr-namespace:WpfApplication12" />
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

в Prism вы обычно делаете tab control областью, так что вам не нужно контролировать коллекцию связанных вкладок.

<TabControl 
    x:Name="MainRegionHost"
    Regions:RegionManager.RegionName="MainRegion" 
    />

теперь представления могут быть добавлены путем регистрации себя в регионе MainRegion:

RegionManager.RegisterViewWithRegion( "MainRegion", 
    ( ) => Container.Resolve<IMyViewModel>( ).View );

и здесь вы можете увидеть специальность "Призма". Представление создается экземпляром ViewModel. В моем случае я разрешаю ViewModel через инверсию контейнера управления (например, Unity или MEF). ViewModel получает вид, введенный через инъекция конструктора и устанавливает себя в качестве контекста данных представления.

альтернативой является регистрация типа представления в контроллере региона:

RegionManager.RegisterViewWithRegion( "MainRegion", typeof( MyView ) );

использование этого подхода позволяет создавать представления позже во время выполнения, например, с помощью контроллера:

IRegion region = this._regionManager.Regions["MainRegion"];

object mainView = region.GetView( MainViewName );
if ( mainView == null )
{
    var view = _container.ResolveSessionRelatedView<MainView>( );
    region.Add( view, MainViewName );
}

поскольку вы зарегистрировали тип представления, представление помещается в правильную область.

У меня есть конвертер, чтобы отделить UI и ViewModel, вот точка ниже:

<TabControl.ContentTemplate>
    <DataTemplate>
        <ContentPresenter Content="{Binding Tab,Converter={StaticResource TabItemConverter}"/>
    </DataTemplate>
</TabControl.ContentTemplate>

вкладка-это перечисление в моем TabItemViewModel, а TabItemConverter преобразует его в реальный пользовательский интерфейс.

в TabItemConverter,просто получить значение и возвращает элемент управления UserControl вам нужно.