I am working on MVVM sample app. I have 2 projects inside my solution in VSC# 2010. In one project (main project) I have a mainwindow.xaml which has two grids, one located on right side and other on the left. Left side grid has a listBox which has items with the help of observablecollection<>. E.g. Voltage, I2C etc are the items. I have also set the selecteditem
property for the listbox which gives me the selecteditem
.
My main query is the grid towards the right side which has a TABCONTROL with one item("CONNECT") added by default. What I need is to add the tabitem (e.g.Voltage tab) inside the tabcontrol when I select the "Voltage" item from listBox.
TabControl and ListBox inside my grid:
<Grid Grid.Column="0" Name="BoardTabSelect" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListBox Name="ButtonPanel" Style="{DynamicResource styleBanner}" ItemsSource="{Binding BoardTabs, Mode=TwoWay}" SelectedItem="{Binding SelectedTab, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Name="BoardtabChanger" Margin="53,27,0,0" Text="{Binding TabOperation}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
My tabcontrol:
<Grid Grid.Row="0" >
<TabControl Name="ConnectTab" Style="{DynamicResource styleBackground}">
<tablocal:CloseableTabItem Header="Connect" x:Name="ConnectMain" MouseDoubleClick="TabItem_MouseDoubleClick">
<DockPanel>
<ListView Name="listView" Height="460" Margin="0,-77,0,0" ItemsSource="{Binding Products}" SelectedItem="{Binding SelectedProduct, Mode=TwoWay}">
<ListView.View>
<GridView>
<GridViewColumn Width="300" Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Width="283" Header="Connection Status" DisplayMemberBinding="{Binding Connection_Status}" />
</GridView>
</ListView.View>
</ListView>
<Button Content="Connect" Height="23" HorizontalAlignment="Stretch" Margin="-920,500,0,0" Name="ConnectBtnGrid" VerticalAlignment="Stretch" Width="100" Command="{Binding Path=ConnectCommand}" />
<Button Content="Update MSP430" Height="23" HorizontalAlignment="Stretch" Margin="-560,500,0,0" Name="UpdateMSPBtn" VerticalAlignment="Stretch" Width="100" />
<Button Content="Disconnect" Height="23" HorizontalAlignment="Stretch" Margin="-220,500,0,0" Name="DisconnectBtn" VerticalAlignment="Stretch" Width="100" Command="{Binding Path=DisconnectCommand}" />
</DockPanel>
</tablocal:CloseableTabItem>
</TabControl>
</Grid>
My ViewModel class is here:
public List<Product> m_Products;
public ObservableCollection<Product> m_BoardTabs;
public ProductViewModel()
{
m_Products = new List<Product>()
{
new Product() {Name = "Bavaria", Connection_Status = "Disconnected"},
new Product() {Name = "Redhook", Connection_Status = "Disconnected"},
};
m_BoardTabs = new ObservableCollection<Product>()
{
new Product() {TabOperation = "Connect"}
};
}
public List<Product> Products
{
get
{
return m_Products;
}
set
{
m_Products = value;
}
}
public ObservableCollection<Product> BoardTabs
{
get
{
return m_BoardTabs;
}
set
{
m_BoardTabs = value;
}
}
/// <summary>
/// get:
/// set:
/// </summary>
private Product m_SelectedItem;
public Product SelectedProduct
{
get
{
return m_SelectedItem;
}
set
{
m_SelectedItem = value;
NotifyPropertyChanged("SelectedProduct");
}
}
private Product m_SelectedTab;
public Product SelectedTab
{
get
{
return m_SelectedTab;
}
set
{
m_SelectedTab = value;
NotifyPropertyChanged("SelectedTab");
onTabChanged();
}
}
void onTabChanged()
{
if (SelectedTab.TabOperation == "Voltage")
{
//Add tab here
}
}
public Product value { get; set; }
/// <summary>
/// get:
/// set:
/// </summary>
private ICommand mUpdater;
public ICommand ConnectCommand
{
get
{
if (mUpdater == null)
mUpdater = new DelegateCommand(new Action(SaveExecuted), new Func<bool>(SaveCanExecute));
return mUpdater;
}
set
{
mUpdater = value;
}
}
public bool SaveCanExecute()
{
return true;
}
public void SaveExecuted()
{
if (SelectedProduct.Connection_Status == "Disconnected" && SelectedProduct.Name == "Bavaria")
{
SelectedProduct.Connection_Status = "Connected";
m_BoardTabs.Add(new Product() { TabOperation = "I2C" });
m_BoardTabs.Add(new Product() { TabOperation = "Voltage" });
m_BoardTabs.Add(new Product() { TabOperation = "Clock" });
m_BoardTabs.Add(new Product() { TabOperation = "Codec" });
m_BoardTabs.Add(new Product() { TabOperation = "EEPROM" });
}
else if (SelectedProduct.Connection_Status == "Disconnected" && SelectedProduct.Name == "Redhook")
{
SelectedProduct.Connection_Status = "Connected";
m_BoardTabs.Add(new Product() { TabOperation = "I2C" });
m_BoardTabs.Add(new Product() { TabOperation = "Voltage" });
m_BoardTabs.Add(new Product() { TabOperation = "Clock" });
m_BoardTabs.Add(new Product() { TabOperation = "Codec" });
m_BoardTabs.Add(new Product() { TabOperation = "EEPROM" });
m_BoardTabs.Add(new Product() { TabOperation = "PCM Route" });
m_BoardTabs.Add(new Product() { TabOperation = "PCM Route #" });
m_BoardTabs.Add(new Product() { TabOperation = "PCM Gen" });
m_BoardTabs.Add(new Product() { TabOperation = "SD Card" });
m_BoardTabs.Add(new Product() { TabOperation = "FPGA" });
m_BoardTabs.Add(new Product() { TabOperation = "PCMPDM" });
m_BoardTabs.Add(new Product() { TabOperation = "Data Gen" });
}
}
Mind you the tabitem "VOLTAGE" which I want to add in my control is part of another project which I mentioned in the beginning. It has its own view, viewmodel and model class. The following is the view in.xaml file which I want to add:
<Grid Name="VoltageTab" Height="572" Width="590" DataContext="{StaticResource VoltageViewModel}" >
// Some UI componments which shud be placed inside VOLTAGE Tab on selecting Voltage from ListBox.
</Grid>
As you can see above, I want the above view to be placed inside the VoltageTab which should get created once user clicks Voltage item from ListBox.
The data template for the tabcontrol should not contain a tabitem. The tabcontrol is generating a tabitem for each element in the bound Collection. To enable databinding to the tabitem header set the itemcontainerstyle property of the tabcontrol. Here is a small sample:
The View:
<Window x:Class="WpfLab.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.5*"/>
</Grid.ColumnDefinitions>
<TabControl ItemsSource="{Binding ProductTabs}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
<ListBox Grid.Column="1" ItemsSource="{Binding Products}" SelectedItem="{Binding SelectedProduct}"/>
</Grid>
The ViewModel
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
namespace WpfLab
{
public partial class MainWindow : Window
{
Product selectProduct;
public MainWindow()
{
InitializeComponent();
Products = new ObservableCollection<Product>();
ProductTabs = new ObservableCollection<Product>();
var products = Enumerable.Range(0, 10).Select(i => new Product { Header = "Product " + i });
foreach (var p in products)
Products.Add(p);
DataContext = this;
}
public Product SelectedProduct
{
get { return this.selectProduct; }
set
{
UpdateTabs(this.selectProduct, value);
this.selectProduct = value;
}
}
public ObservableCollection<Product> Products { get; private set; }
public ObservableCollection<Product> ProductTabs { get; private set; }
void UpdateTabs(Product old, Product @new)
{
if (ProductTabs.Any(p => p == old))
ProductTabs.Remove(old);
ProductTabs.Add(@new);
}
}
public class Product
{
public string Header { get; set; }
public override string ToString()
{
return Header;
}
}
}