TabControls containing different user controls usi

2019-05-11 22:40发布

问题:

I am making a WPF application following MVVM. What I want in my application is that there is a View which contains some common buttons and text boxes and a TabControl. TabControl will basically host different UserControls. So for each UserControl I have a separate View and a ViewModel ready.

So structure of my application looks like this.

MainWindow.Xaml
    EntryView.Xaml
        Button1
        Button2
        TabControl
            UserControl1 (View)
            UserControl2 (View)
            UserControl3 (View)

Son in my EntryView I have the tab control. Now I need to bind this.

Here is what I have done.

EntryView.Xaml

<TabControl ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}">
    <TabControl.ContentTemplate>
        <DataTemplate DataType="{x:Type vm:UserControl1ViewModel}">
            <v:UserControl1View/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:UserControl2ViewModel}">
            <v:UserControl2View/>
        </DataTemplate>
    </TabControl.ContentTemplate>
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="Header"/>
        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>

EntryViewModel.cs

private ObservableCollection<BaseViewModel> _tabs;
public ObservableCollection<BaseViewModel> Tabs
{
    get
    {
        if (_tabs == null)
        {
            _tabs = new ObservableCollection<BaseViewModel>();
            _tabs.Add(new UserControl1ViewModel());
            _tabs.Add(new UserControl2ViewModel());
        }
        return _tabs;
    }
}

But now when I run my application nothings happens. TabControl is empty. I put breakpoint inside Tabs in view model, but it didn't get hit. So question one is am I doing this right? If no then what should I do?

回答1:

For starters I don't know how it compiles on your machine as on my machine it gives me this error:

The property "ContentTemplate" can only be set once.

However when I move DataTemplates to TabControl.Resources it compiles and works fine:

<TabControl>
   <TabControl.Resources>
      <DataTemplate DataType="{x:Type vm:UserControl1ViewModel}">
         <v:UserControl1View/>
      </DataTemplate>
      <DataTemplate DataType="{x:Type vm:UserControl2ViewModel}">
         <v:UserControl2View/>
      </DataTemplate>
   </TabControl.Resources>
   <TabControl.ItemTemplate>
      <DataTemplate>
         <TextBlock Text="Header"/>
      </DataTemplate>
   </TabControl.ItemTemplate>
</TabControl>


回答2:

The real culprit is simply that

<TabControl.ContentTemplate>

Takes only one DataTemplate element as content. That property cannot be set twice.

Instead giving a DataTemplate for each type in your TabControl's (or the window's) resources will do just fine.

Ideally it seems to me that you'd simply add the UserControlViews to your ItemsSource and the views can set their own DataContext to the ViewModels.