简体   繁体   中英

Inject view into TabControl using prism library

That's how I defined TabControl :

<TabControl ItemsSource="{Binding OpenedProjects, UpdateSourceTrigger=PropertyChanged}"
            SelectedItem="{Binding SelectedProject, Mode=OneWay}">
    <!-- headers -->
    <!-- header definition is unimportant for this question -->

    <!-- content -->
    <TabControl.ContentTemplate>
        <DataTemplate>
            <local:ProjectView />
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

And these are the two methods I have defined in my Module class, that are used to register and use views:

protected override void _initializeViews() {
    _container.RegisterType<MainMenuView>();
    _container.RegisterType<ProjectsView>();
    _container.RegisterType<ProjectView>();
    _container.RegisterType<ContentView>();
}

protected override void _initializeRegions() {
    IRegion menuRegion = _regionManager.Regions[RegionNames.MainMenuRegion];
    IRegion projectsRegion = _regionManager.Regions[RegionNames.ProjectsRegion];
    IRegion contentRegion = _regionManager.Regions[RegionNames.ContentRegion];

    menuRegion.Add(_container.Resolve<MainMenuView>());
    projectsRegion.Add(_container.Resolve<ProjectsView>());
    contentRegion.Add(_container.Resolve<ContentView>());
}

And the View constructor:

public ProjectView(ProjectsViewModel vm) {
    InitializeComponent();
    DataContext = vm;
}

What I want to achieve is to inject ProjectView into TabControl 's content area. Obviously, currently it doesn't work because of the ViewModel argument in the above constructor. How can I create this functionality, the PRISM way?

EDIT:

I found this: How to inject views into TabControl using Prism? however if I do the same as the author of that question, I'm getting:

System.InvalidOperationException: ItemsControl's ItemsSource property is not empty.

You TabControl didn't have a region so you can't inject something into your TabControl. Otherwise you only use simple MVVM to inject something into your view.

To use Prism to inject something in your TabControl. You only need this line:

<TabControl prism:RegionManager.RegionName="TabRegion"/>

And then you can inject something very easy into your View.

_regionManager.RequestNavigate("TabRegion", new Uri("ProjectView", UriKind.Relative));

Before that you have to add the View to your Containier with:

UnityContainer.RegisterType<object, ProjectView>("ProjectView");

To add the Headertext you can easy changed the Style of the TabItem and bind the Header to the ViewModel from the ProjectView:

<UserControl.Resources>
    <Style TargetType="TabItem">
        <Setter Property="Header" Value="{Binding DataContext.Name}" />
    </Style>
</UserControl.Resources>

I hope that was the answer you looking for^^

The answer from @ascholz help me to implement this. Although the last step didn't work for me:

<UserControl.Resources>
    <Style TargetType="TabItem">
        <Setter Property="Header" Value="{Binding DataContext.Name}" />
    </Style>
</UserControl.Resources>

What i did instead was:

1 - Create a Tab Control with a prism region (Inside MainWindows in my case).

<TabControl prism:RegionManager.RegionName="TabRegion"/>

2 - Create a "user control" of type TabItem (NewTabView) that holds the tab views. Note that i'm binding the Header here. The idea here would be to add a region here as well inside the grid (for the content of the tab), or to make every control that needs to be inside the tab a child of TabItem.

<TabItem 
    x:Class="Client.WPF.Views.NewTab"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:prism="http://prismlibrary.com/"             
    prism:ViewModelLocator.AutoWireViewModel="True"
    Header="{Binding Title}">
    <Grid>
        <Button Content="{Binding RandomNumber}"/>
    </Grid>
</TabItem>
///The code behind should inherit from TabItem as well
public partial class NewTab : TabItem
///The viewmodel has a "Title" property
        private string _title = "New Tab";
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }

4 - Finally, i navigate to the NewTab like this (MainWindowViewModel code)

        public DelegateCommand NewTab { get; }

        public MainWindowViewModel(IRegionManager regionManager, IEventAggregator eventAggregato)
        {
            this.regionManager = regionManager;
            this.eventAggregator = eventAggregator;

            NewTab = new DelegateCommand(NewTabAction);
        }

        private void NewTabAction()
        {
            regionManager.RequestNavigate("TabRegion", "NewTab");
        }

5 - As an added bonus, if you want to allow more than 1 instance of the tab, you can do something like this on the view model (NewTabViewModel).

///First add the IConfirmNavigationRequest interface
public class NewTabViewModel : BindableBase, IConfirmNavigationRequest
///...
///Then the implementation should look like this
        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
        {

            continuationCallback(true);///Will allow multiple instances (tabs) of this view
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {

        }

        public bool IsNavigationTarget(NavigationContext navigationContext)
        {

            return false;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {

        }

Or you could also add views directly to the region. Although you would need to resolve views using the IContainerProvider. Something like this:

var view = containerProvider.Resolve<NewTab>();
regionManager.Regions["TabRegion"].Add(view);

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