我正在研究MVVM示例应用。我在VSC#2010的解决方案中有2个项目。在一个项目(主项目)中,我有一个mainwindow.xaml,它有两个网格,一个位于右侧,另一个位于左侧。左侧网格有一个listBox,它有observablecollection<>的帮助项目。例如。电压,I2C等是项目。我还为列表框设置了selecteditem
属性,该属性为selecteditem
。
我的主要查询是右侧的网格,其中有一个TABCONTROL默认添加了一个项目(“CONNECT”)。我需要的是当我从listBox中选择“Voltage”项时,在tabcontrol中添加tabitem(例如,Voltage选项卡)。
我网格中的TabControl和ListBox:
<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>
我的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>
我的ViewModel类位于:
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" });
}
}
请注意,我希望在我的控制中添加的标题“VOLTAGE”是我在开头提到的另一个项目的一部分。它有自己的视图,视图模型和模型类。以下是我要添加的in.xaml文件视图:
<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>
如上所示,我希望将上面的视图放在VoltageTab中,一旦用户点击ListBox中的Voltage项,就会创建它。
答案 0 :(得分:0)
TabControl有一个ItemsSource属性..这可以绑定到ViewModel中可观察的对象集合。
与此同时,可观察集合中使用的对象必须具有关联的DataTemplate,该DataTemplate应该是TabItem。
因此,当您使用DataTemplate将对象添加到ObservableCollection作为TabControl的源时,会将新的TabItem添加到TabControl。
还要确保初始tabitem的observablecollection中有一个条目/对象。
您可以通过添加适当的命名空间/引用来引用DataTemplate中其他项目的TabItem
这是ViewModel类
public class TabItemDetail
{
public string Header { get; set; }
}
public class MainWindowViewModel : INotifyPropertyChanged
{
#region Members
List<string> _dataSource = null;
string _selectedDataSource = null;
ObservableCollection<TabItemDetail> _tabItems = null;
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public ObservableCollection<TabItemDetail> Items
{
get
{
if (_tabItems == null)
{
_tabItems = GetTabItems();
}
return _tabItems;
}
}
public List<string> DataSource
{
get
{
if (_dataSource == null)
{
_dataSource = GetDataSource();
}
return _dataSource;
}
}
public string SelectedDataSource
{
get { return _selectedDataSource; }
set
{
if (_selectedDataSource == value)
return;
_selectedDataSource = value;
AddItemsToTab(value);
OnPropertyChanged("SelectedDataSource");
}
}
#region Private methods
private void AddItemsToTab(string selectedItem)
{
if (_tabItems != null && _tabItems.Count > 0)
{
var query = from item in _tabItems
where item.Header == selectedItem
select item;
if (query.Count() == 1)
return;
else
_tabItems.Add(new TabItemDetail { Header = selectedItem });
}
}
private List<string> GetDataSource()
{
List<string> source = new List<string>();
source.Add("Default tab");
source.Add("Voltage Tab");
return source;
}
private ObservableCollection<TabItemDetail> GetTabItems()
{
ObservableCollection<TabItemDetail> newSource = new ObservableCollection<TabItemDetail>();
newSource.Add(new TabItemDetail { Header = "Connect" });
return newSource;
}
#endregion
}
这是视图
<Window x:Class="SampleApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SampleApp"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type local:TabItemDetail}">
<TabItem Header="{Binding Header}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" ItemsSource="{Binding DataSource}" SelectedItem="{Binding SelectedDataSource}"/>
<TabControl Grid.Column="2" local:MySampleAttachedProperty.Header="{Binding SelectedDataSource}">
<TabItem Header ="Connect" />
</TabControl>
</Grid>
这是新的附加属性类,它可以实现技巧
public class MySampleAttachedProperty
{
public static string GetHeader(DependencyObject obj)
{
return (string)obj.GetValue(HeaderProperty);
}
public static void SetHeader(DependencyObject obj, string value)
{
obj.SetValue(HeaderProperty, value);
}
// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.RegisterAttached("Header", typeof(string), typeof(MySampleAttachedProperty), new UIPropertyMetadata(CallBack));
private static void CallBack(object sender, DependencyPropertyChangedEventArgs args)
{
TabControl tabControl = sender as TabControl;
TabItem newTab = new TabItem { Header = args.NewValue };
tabControl.Items.Add(newTab);
newTab.Focus();
}
}
答案 1 :(得分:0)
tabcontrol的数据模板不应包含tabitem。 tabcontrol为绑定Collection中的每个元素生成一个tabitem。要启用数据绑定到tabitem标头,请设置tabcontrol的itemcontainerstyle属性。这是一个小样本:
观点:
<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>
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;
}
}
}