如何将TabControl绑定到ViewModels的集合?

| 基本上我在MainViewModel.cs中:
ObservableCollection<TabItem> MyTabs { get; private set; }
但是,我需要以某种方式不仅可以创建选项卡,还可以在维护MVVM的同时将选项卡的内容加载并链接到其相应的视图模型。 基本上,我如何才能将用户控件作为Tabitem的内容加载,并使该用户控件连接到适当的视图模型。造成这一困难的部分是ViewModel不应构造实际的视图项,对吗?可以吗 基本上,这是否适合MVVM:
UserControl address = new AddressControl();
NotificationObject vm = new AddressViewModel();
address.DataContext = vm;
MyTabs[0] = new TabItem()
{
    Content = address;
}
我只问是因为,好吧,我正在从ViewModel内部构造一个View(AddressControl),在我看来,这听起来像是MVVM。     
已邀请:
这不是MVVM。您不应在视图模型中创建UI元素。 您应该将Tab的ItemsSource绑定到ObservableCollection,并且应该包含带有应创建的选项卡信息的模型。 这是代表选项卡页面的VM和模型:
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中,通常使选项卡控件成为一个区域,这样您就不必控制绑定的选项卡页面集合。
<TabControl 
    x:Name=\"MainRegionHost\"
    Regions:RegionManager.RegionName=\"MainRegion\" 
    />
现在,可以通过将其自身注册到区域MainRegion中来添加视图:
RegionManager.RegisterViewWithRegion( \"MainRegion\", 
    ( ) => Container.Resolve<IMyViewModel>( ).View );
在这里,您可以看到棱镜的特长。 View由ViewModel实例化。就我而言,我是通过控制反转容器(例如Unity或MEF)解析ViewModel的。 ViewModel通过构造函数注入获得注入的View,并将其自身设置为View的数据上下文。 另一种方法是将视图的类型注册到区域控制器中:
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>
Tab是我的TabItemViewModel中的枚举,并且TabItemConverter将其转换为真实的UI。 在TabItemConverter中,只需获取值并返回所需的用户控件即可。     
可能是这样的:
<UserControl x:Class=\"Test_002.Views.MainView\"
         xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"
         xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"
         xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" 
         xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" 
         xmlns:local=\"clr-namespace:Test_002.Views\"
         xmlns:generalView=\"clr-namespace:Test_002.Views.General\"
         xmlns:secVIew=\"clr-namespace:Test_002.Views.Security\"
         xmlns:detailsView=\"clr-namespace:Test_002.Views.Details\"
         mc:Ignorable=\"d\" 
         d:DesignHeight=\"400\" d:DesignWidth=\"650\">
<Grid>
    <DockPanel>
        <StackPanel Orientation=\"Horizontal\" DockPanel.Dock=\"Bottom\" Margin=\"2,5\">
            <Button Command=\"{Binding btnPrev}\" Content=\"Prev\"/>
            <Button Command=\"{Binding btnNext}\" Content=\"Next\"/>
            <Button Command=\"{Binding btnSelected}\" Content=\"Selected\"/>
        </StackPanel>
        <TabControl>
            <TabItem Header=\"General\">
                <generalView:GeneralView></generalView:GeneralView>
            </TabItem>
            <TabItem Header=\"Security\">
                <secVIew:SecurityView></secVIew:SecurityView>
            </TabItem>
            <TabItem Header=\"Details\">
                <detailsView:DetailsView></detailsView:DetailsView>
            </TabItem>
        </TabControl>
    </DockPanel>
</Grid>
认为这是最简单的方法。 MVVM兼容吗?     

要回复问题请先登录注册