Re: Custom TabPage/TabItem
You don't really need to create special classes for each Tab page, you can define them in the TabControl itself:
xml Code:
<TabControl>
<TabItem Header="Custom Tab">
<StackPanel>
<TextBox x:Name="CT1"/>
<TextBox x:Name="CT2"/>
</StackPanel>
</TabItem>
<TabItem Header="Tab 2">
<Rectangle Fill="AntiqueWhite" Height="30" HorizontalAlignment="Stretch" />
</TabItem>
</TabControl>
What are you trying to achieve? Some kind of reuse of standard UI panels? You probably want to define a UserControl that represents the content of your tab page in that case, and then use that UserControl in your TabControl->TabItem XAML.
Re: Custom TabPage/TabItem
The tabs are added dynamically and I need some code to run behind them, hence, I need a class.
Re: Custom TabPage/TabItem
The dynamic code - is it dealing with the behaviour of the tabs? If not, you can have the code-behind in the UserControl.
To add a tab dynamically, bind the ItemsSource property of your TabControl to a Collection of objects that represent your tab pages. As you add/remove from this collection, the TabControl will add/remove tabs.
For example, assuming this class as representing your tab pages:
csharp Code:
public class MyTabPageViewModel : INotifyPropertyChanged
{
private string m_headerText;
private string m_customText1;
private string m_customText2;
public string HeaderText
{
get { return m_headerText; }
set
{
if (m_headerText != value)
{
m_headerText = value;
OnPropertyChanged("HeaderText");
}
}
}
public string CustomText1
{
get { return m_customText1; }
set
{
if (m_customText1 != value)
{
m_customText1 = value;
OnPropertyChanged("CustomText1");
}
}
}
public string CustomText2
{
get { return m_customText2; }
set
{
if (m_customText2 != value)
{
m_customText2 = value;
OnPropertyChanged("CustomText2");
}
}
}
#region Implementation of INotifyPropertyChanged
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
and that you have a window view model looking something like this:
csharp Code:
public class MyWindowViewModel
{
private readonly ObservableCollection<MyTabPageViewModel> m_tabPages;
private readonly ReadOnlyObservableCollection<MyTabPageViewModel> m_readonlyTabPages;
public MyWindowViewModel()
{
m_tabPages = new ObservableCollection<MyTabPageViewModel>();
m_readonlyTabPages = new ReadOnlyObservableCollection<MyTabPageViewModel>(m_tabPages);
m_addTabCommand = new DelegateCommand(AddATab);
AddATab();
AddATab();
}
private int i = 1;
private ICommand m_addTabCommand;
private void AddATab()
{
MyTabPageViewModel myTabPageViewModel =
new MyTabPageViewModel()
{
HeaderText = string.Format("Tab Page {0}", i++)
};
m_tabPages.Add(myTabPageViewModel);
}
public ReadOnlyObservableCollection<MyTabPageViewModel> TabPages
{
get { return m_readonlyTabPages; }
}
public ICommand AddTabCommand
{ get { return m_addTabCommand; } }
}
internal class DelegateCommand : ICommand
{
private readonly Action m_onExecute;
public DelegateCommand(Action onExecute)
{
m_onExecute = onExecute;
}
#region Implementation of ICommand
public void Execute(object parameter)
{
m_onExecute();
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
#endregion
}
Then you need to firstly define a template for what the tab page looks like:
xml Code:
<DataTemplate DataType="{x:Type local:MyTabPageViewModel}">
<StackPanel>
<TextBox Text="{Binding CustomText1}" />
<TextBox Text="{Binding CustomText2}" />
</StackPanel>
</DataTemplate>
(this is a default template, you might want to give it a key and then reference it explicitly in the TabControl...)
Then you can bind you TabControl thus:
xml Code:
<TabControl ItemsSource="{Binding TabPages}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding HeaderText}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
This uses the TabPages property from the Window view model (that is set as the DataContext of the window) as the ItemsSource, so each TabItem in the TabControl gets an element from that collection as its DataContext. We use a style to define the Header property of each TabItem as bound to the HeaderText property of the TabPageViewModel so that we get the correct text in the header. The Content of each TabItem remains as the whole TabPageViewModel, which is rendered using the DatATemplate we defined earlier. The AddTabCommand can be wired up to a button on your window to test adding tab pages:
xml Code:
<Button Command="{Binding AddTabCommand}">Add a Tab</Button>