IdanB
IdanB

Reputation: 333

bind different modelview and view to each TabItem via MVVM in WPF

I'm using MVVM to dynamically create tabs from viewModel. In code, my attempt is to hold collection of "TabItem" that specify how tab appears (custom template) & in addition ModelView object, and then based on modelview display on the TabItem view #1 / or view #2.

My current s/w architecture is as follows:

My MainWindow.xaml:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ViewModel="clr-namespace:MyApp.ViewModel" x:Class="MyApp.MainWindow"
    xmlns:Views="clr-namespace:MyApp.View"
    Height="700" Width="1000" Background="#FF1B0000" ResizeMode="NoResize">

<Window.DataContext>
    <ViewModel:TabItemViewModel/>
</Window.DataContext>
<Grid>

    <TabControl Background="Black" Margin="0,25,0,0" BorderThickness="0,0,0,0" ItemsSource="{Binding Tabs}" BorderBrush="Black" >

            <TabControl.ItemTemplate>
                <!-- this is the header template-->
                <DataTemplate>
                    <Grid Margin="0">
                        <Border Margin="0,0,0,0" 
                            Background="Black"
                            BorderBrush="Black" 
                            BorderThickness="0,0,0,0" Padding="0,0,0,0">
                            <StackPanel   Orientation="Horizontal"
                                        Margin="0,0,0,0">
                                <Image Name ="tabImage" Source="{Binding TabImage_Disabled}" />
                            </StackPanel>
                        </Border>
                    </Grid>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent}}" Value="True">
                            <Setter TargetName="tabImage" Property="Source" Value="{Binding TabImage_Enabled}"/>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </TabControl.ItemTemplate>
            <TabControl.ContentTemplate>
                <!-- this is the body of the TabItem template-->
                <DataTemplate>
                    <TextBlock Text="{Binding TabContents}" Foreground="white" />
                </DataTemplate>
            </TabControl.ContentTemplate>
       </TabControl>


    </Grid>
</Window>

TabItem.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media.Imaging;
using MyApp.ViewModel;

namespace MyApp.Model
{
    public sealed class TabItem
    {
        public string TabName { get; set; }
        public BitmapImage TabImage_Enabled { get; set; }
        public BitmapImage TabImage_Disabled { get; set; }
        public BitmapImage TabImage_Background { get; set; }
        public ViewModelBase TabContents { get; set; }
    }
}

ViewModelBase.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyApp.ViewModel
{
    public class ViewModelBase : INotifyPropertyChanged
    {

         public event PropertyChangedEventHandler PropertyChanged;

         protected virtual void RaisePropertyChanged(string propertyName)
         {
              var handler = this.PropertyChanged;
              if (handler != null)
              {
                  handler(this, new PropertyChangedEventArgs(propertyName));
              }
         }
    }
}

TabItemViewModel.cs:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Media.Imaging;
using MyApp.Model;

namespace MyApp.ViewModel
{
public sealed class TabItemViewModel : ViewModelBase
{

    const int NUMBER_OF_TABS = 2;

    enum enum_Tabs
    {
        Research_Tab = 0,
        Engineering_Tab = 1
    }

    Uri[] _aUrisEnabled = new Uri[NUMBER_OF_TABS];
    Uri[] _aUrisDisabled = new Uri[NUMBER_OF_TABS];
    Uri[] _aUrisBackgroundPics = new Uri[NUMBER_OF_TABS];
    BitmapImage[] _aEnabledTabImages = new BitmapImage[NUMBER_OF_TABS];
    BitmapImage[] _aDisabledTabImages = new BitmapImage[NUMBER_OF_TABS];
    BitmapImage[] _aBackgroundTabImages = new BitmapImage[NUMBER_OF_TABS];

    private ObservableCollection<TabItem> _tabs;

    public ObservableCollection<TabItem> Tabs
    {
        get { return _tabs; }
        set
        {
            _tabs = value;
            RaisePropertyChanged("Tabs");
        }
    }

    public TabItemViewModel()
    {
        Tabs = new ObservableCollection<TabItem>();


        // URIs

        // enabled pics
        _aUrisEnabled[(int)enum_Tabs.Research_Tab] = new Uri("pack://application:,,,/Images/research_enabled.png");
        _aUrisEnabled[(int)enum_Tabs.Engineering_Tab] = new Uri("pack://application:,,,/Images/engineering_enabled.png");

        // disabled pics
        _aUrisDisabled[(int)enum_Tabs.Research_Tab] = new Uri("pack://application:,,,/Images/research_disabled.png");
        _aUrisDisabled[(int)enum_Tabs.Engineering_Tab] = new Uri("pack://application:,,,/Images/engineering_disabled.png");

        // Tab backgrounds
        _aUrisBackgroundPics[(int)enum_Tabs.Research_Tab] = new Uri("pack://application:,,,/Images/research_background.png");
        _aUrisBackgroundPics[(int)enum_Tabs.Engineering_Tab] = new Uri("pack://application:,,,/Images/engineering_background.png");

        // Load all images
        for (int iImageIndex = 0; iImageIndex < NUMBER_OF_TABS; iImageIndex++)
        {
            _aEnabledTabImages[iImageIndex] = new BitmapImage(_aUrisEnabled[iImageIndex]);
            _aDisabledTabImages[iImageIndex] = new BitmapImage(_aUrisDisabled[iImageIndex]);
            _aBackgroundTabImages[iImageIndex] = new BitmapImage(_aUrisBackgroundPics[iImageIndex]);
        }


        Tabs.Add(new TabItem { TabName = "Research", TabImage_Enabled = _aEnabledTabImages[(int)enum_Tabs.Research_Tab], TabImage_Disabled = _aDisabledTabImages[(int)enum_Tabs.Research_Tab], TabImage_Background = _aBackgroundTabImages[(int)enum_Tabs.Research_Tab], TabContents = new TabResearchViewModel() });
        Tabs.Add(new TabItem { TabName = "Engineering", TabImage_Enabled = _aEnabledTabImages[(int)enum_Tabs.Engineering_Tab], TabImage_Disabled = _aDisabledTabImages[(int)enum_Tabs.Engineering_Tab], TabImage_Background = _aBackgroundTabImages[(int)enum_Tabs.Engineering_Tab], TabContents = new TabEngineeringViewModel() });
         }

     }
}

My problem id how do i specify custom template (for TabHeader, since im showing picture instead of TextBlock) in addition to view.

I've tried searching on google & on this site, but couldn't find solution that use custom template. I've found some solution of TempleateSelector, but i'm unsure as to how combine it with MVVM.

I've also attempted to write something like this in MainWIndow.xaml:

        <TabControl Background="Black" Margin="0,25,0,0" BorderThickness="0,0,0,0"  ItemsSource="{Binding Tabs}" BorderBrush="Black" >

            <TabControl.Resources>
                <DataTemplate DataType="{x:Type ViewModel:TabResearchViewModel}">
                    <Views:TabResearchView />
                </DataTemplate>
                <DataTemplate DataType="{x:Type ViewModel:TabEngineeringViewModel}">
                    <Views:TabEngineeringView />
                </DataTemplate>
            </TabControl.Resources>

        ... (removed for clarity)

I want to replace the <TextBlock Text="{Binding TabContents}" Foreground="white" /> </DataTemplate> with something that will display "view" (page), while binding to the tabs collection...

Would appreciate any help on matter. Thanks in advanced...

Upvotes: 0

Views: 3699

Answers (1)

IdanB
IdanB

Reputation: 333

Nevermind, i've figured it out myself.

My solution was: 1. replace views from Page to UserControl 2. replace "TextBlock" line with this line:

<ContentPresenter Content="{Binding TabContents}" />

Upvotes: 1

Related Questions