Search code examples
c#wpfunity-containerprismioc-container

Register the same view twice to TabControl with different behavior


I search for a smart way to instantiate one View and ViewModel multiple times in a Tabcontrol with slightly different behavior. In best case by using Prism7.1

My current solution is;

in my MainView

        <TabControl
            ItemsSource="{Binding TabItemCollection}"
            SelectedItem="{Binding SelectedTabItem}"
            ItemContainerStyle="{DynamicResource ItemSize20_HeaderBinding}" 
            mah:TabControlHelper.Underlined="SelectedTabItem">
            <TabControl.Resources>
                <DataTemplate DataType="{x:Type vm:MaskingCreationViewModel}" >
                    <local:MaskingCreation/>
                </DataTemplate>
            </TabControl.Resources>
        </TabControl>

in my MainViewModel

    public class MainViewModel
    {
        public ObservableCollection<MaskingCreationViewModel> TabItemCollection { get; set; }
        public MaskingCreationViewModel SelectedTabItem { get; set; }

        public MainViewModel()
        {
            TabItemCollection = new ObservableCollection<MaskingCreationViewModel>();
            TabItemCollection.Add(new MaskingCreationViewModel(new TabBehaviorA()));
            TabItemCollection.Add(new MaskingCreationViewModel(new TabBehaviorB()));

            SelectedTabItem = TabItemCollection[0];
        }
    }

Here I want to inject the "TabBehavior" in my ViewModel provide the different behavior. I tried that already with Prism to register the "MaskingCreation" in the TabControl via Region, but with that I get two problems.

  1. If I normal register the View with the region a don't have the chance to inject the behavior I want.
            regionManager.RegisterViewWithRegion(Regions.Masking, typeof(MaskingCreation));
  1. if I use this I have a problem with every line of this.
    • I want to get a new Instance from the ServiceLocation with exact this variation of TabBehavior, but I don't know how this should work.
    • Becaus I don't get this Consturctor injection to work I have to provide a property for the TabBehavior class.
    • And the last and worst thing. I have to store a reference of the View in my ViewModel. I want to avoid using of the DataContext inside my ViewModel.
            regionManager.RegisterViewWithRegion(Regions.Masking, () => 
            {
                var vm = ServiceLocator.Current.GetInstance<MaskingCreationViewModel>();
                vm.Behavior = new TabBehaviorB();
                return vm.GetView();
            });

Did anybody know a smart solution that fits in the MVVM pattern?


Solution

  • In the view model, I'd inject a factory for MaskingCreationViewModel and all the tab behaviors:

    internal class MainViewModel : BindableBase
    {
        public MainViewModel( IMaskingCreationViewModelFactory maskingCreationViewModelFactory, IEnumerable<ITabBehavior> tabBehaviors )
        {
            foreach (var tabBehavior in tabBehaviors)
                TabItemCollection.Add( maskingCreationViewModelFactory.Create( tabBehavior ) );
    
            SelectedTabItem = TabItemCollection.FirstOrDefault();
        }
    
        public ObservableCollection<MaskingCreationViewModel> TabItemCollection { get; } = new ObservableCollection<MaskingCreationViewModel>();
        public MaskingCreationViewModel SelectedTabItem { get => _selectedTabItem; set => SetProperty( ref _selectedTabItem, value ); }
    
        private MaskingCreationViewModel _selectedTabItem;
    }