Reputation: 333
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
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