简体   繁体   中英

Showing Multiple Control Types in TabControl

All, I have created a TabControl to hold Tabitem s that contain a single control type. The markup for MainWindow.xaml was as shown below

...
<TabControl x:Name="tabControl" 
            ItemsSource="{Binding Path=Workspaces}" 
            SelectedIndex="{Binding SelectedIndex}"
            IsSynchronizedWithCurrentItem="true" 
            HorizontalContentAlignment="Stretch" 
            VerticalContentAlignment="Stretch" 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch" 
            TabStripPlacement="Top" 
            Margin="5,0,5,0">
    <TabControl.ItemContainerStyle>
        <Style TargetType="TabItem">
            <Setter Property="Header" Value="{Binding Path=DisplayName}"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Stretch"/>
        </Style>
    </TabControl.ItemContainerStyle>
    <TabControl.ContentTemplate>
        <DataTemplate>
            <Views:ResourceControl DataContext="{Binding}" 
                                   HorizontalAlignment="Stretch" 
                                   VerticalAlignment="Stretch"/>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>
...

This worked great for my Views:ResourceControl s but I now want to extend the type of controls displayed in the TabControl . To do this I create controls that are both linked to view models that inherit from a base 'WorkspaceViewModel' and I have created the following resource file

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:ViewModels="clr-namespace:ResourceStudio.ViewModels"
                    xmlns:Views="clr-namespace:ResourceStudio.Views">
    <DataTemplate DataType="{x:Type ViewModels:ResourceDataViewModel}">
        <Views:ResourceControl />
    </DataTemplate>
    <DataTemplate DataType="{x:Type ViewModels:StartPageViewModel}">
        <Views:StartPageControl/>
    </DataTemplate>
    <DataTemplate x:Key="WorkspacesTemplate">
        <TabControl x:Name="tabControl" 
                    IsSynchronizedWithCurrentItem="true" 
                    ItemsSource="{Binding}" 
                    SelectedIndex="{Binding SelectedIndex}"
                    HorizontalContentAlignment="Stretch" 
                    VerticalContentAlignment="Stretch" 
                    HorizontalAlignment="Stretch" 
                    VerticalAlignment="Stretch" 
                    TabStripPlacement="Top" 
                    Margin="5,0,5,0">
            <TabControl.ItemContainerStyle>
                <Style TargetType="TabItem">
                    <Setter Property="Header" Value="{Binding Path=DisplayName}"/>
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                    <Setter Property="VerticalContentAlignment" Value="Stretch"/>
                </Style>
            </TabControl.ItemContainerStyle>
        </TabControl>
    </DataTemplate>
</ResourceDictionary>

and now in the MainWindow.xaml I have

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="MainWindowResources.xaml" />
        </ResourceDictionary.MergedDictionaries>
        <Style x:Key="DescriptionHeaderStyle" TargetType="Label">
            <Setter Property="FontSize" Value="22" />
            <Setter Property="HorizontalAlignment" Value="Center" />
        </Style>
    </ResourceDictionary>
</Window.Resources>
...
<ContentControl
    Content="{Binding Path=Workspaces}" 
    ContentTemplate="{StaticResource WorkspacesTemplate}">
</ContentControl>

The bindings seem to register for the different views I want to display as the tabs display with the relevant headers. However, the actual controls do not display until I load another form. It seems that the SelectedIndex is not binding and the views not being updated when the tab item is switched/loaded.

How can I change the WorkspaceTemplate to fix this problem?

Thanks for your time.


Edit. Requested information regarding the MainViewModel.

public class MainWindowViewModel : WorkspaceViewModel 
{
    private readonly IDialogService dialogService;
    private WorkspaceViewModel selectedWorkspace;
    private ObservableCollection<WorkspaceViewModel> workspaces;
    private Dictionary<string, string> resourceDictionary;

    public MainWindowViewModel()
    {
        base.DisplayName = "SomeStringName";
        resourceDictionary = new Dictionary<string, string>();
        dialogService = ServiceLocator.Resolve<IDialogService>();
        Contract.Requires(dialogService != null);
    }

    ...

    private void OnWorkspacesChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null && e.NewItems.Count != 0)
            foreach (WorkspaceViewModel workspace in e.NewItems)
                workspace.RequestClose += this.OnWorkspaceRequestClose;

        if (e.OldItems != null && e.OldItems.Count != 0)
            foreach (WorkspaceViewModel workspace in e.OldItems)
                workspace.RequestClose -= this.OnWorkspaceRequestClose;
    }

    private void OnWorkspaceRequestClose(object sender, EventArgs e)
    {
        WorkspaceViewModel workspace = sender as WorkspaceViewModel;
        workspace.Dispose();
        int currentIndex = Workspaces.IndexOf(workspace);
        this.Workspaces.Remove(workspace);
        if (this.Workspaces.Count > 0)
            this.SetActiveWorkspace(Workspaces[currentIndex - 1]);
    }

    private void SetActiveWorkspace(WorkspaceViewModel workspace)
    {
        Debug.Assert(this.Workspaces.Contains(workspace));
        ICollectionView collectionView = CollectionViewSource.GetDefaultView(this.Workspaces);
        if (collectionView != null)
            collectionView.MoveCurrentTo(workspace);
    }

    public WorkspaceViewModel SelectedWorkspace
    {
        get { return selectedWorkspace; }
        set { selectedWorkspace = value; }
    }   

    private int selectedIndex = 0;
    public int SelectedIndex
    {
        get { return selectedIndex; }
        set
        {
            if (selectedIndex == value)
                return;
            selectedIndex = value;
            OnPropertyChanged("SelectedIndex");
        }
    }

    /// <summary>
    /// Returns the collection of available workspaces to display.
    /// A 'workspace' is a ViewModel that can request to be closed.
    /// </summary>
    public ObservableCollection<WorkspaceViewModel> Workspaces
    {
        get
        {
            if (workspaces == null)
            {
                workspaces = new ObservableCollection<WorkspaceViewModel>();
                workspaces.CollectionChanged += this.OnWorkspacesChanged;
            }
            return workspaces;
        }
    }
    ...
}

I faced something similar by using your code. Not sure if it is the same one. When my application loaded it showed the 1st tab (0th) with its proper content. When select the 2nd content region got blank and nothing happened.

I moved the Content="{Binding Path=Workspaces}" to the TabControl ie

Content="{Binding}" and

<TabControl ItemsSource="{Binding Workspaces}"/> 

and it started to show the content for the tabs. I used more stripped down version of your VM. just the collection of WorkSpaces .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM