Data Binding - Tab Control
-
Sunday, June 15, 2008 12:45 PM
Has anyone had luck with data binding with a Tab Control? I get a stack trace error when I add the TabControl in the ItemsPanelTemplate content area. When I place the TabControl in the ItemsTemplate, it works but displays the tabs as different entities (because it is rendering them one per item).
I want to have dynamic tabs based on the categories in the xml file. This is what I have. Is there a way to have it work in the ItemsPanelTemplate so it would be a single TabControl with data binded elements? I also tried to use TabControl, rather than ItemsControl but then I got an error "unable to cast from <class> to TabItem".
<
ItemsControl.ItemTemplate> <DataTemplate> <y:TabControl> <y:TabItem Header="{Binding Name}" /> </y:TabControl> </DataTemplate> </ItemsControl.ItemTemplate>This is a similar issue. The problem with the workaround is that my content is purely in xml (category for tabs and children data for tab items).
All Replies
-
Tuesday, June 17, 2008 3:25 AM
Hello, you need a Converter. Try this:
Suppose your data source is something like this:
public class TabSource
{
public object Header { get; set; }
public object Content { get; set; }
}You need a Converter to convert a list of your data source to a list of TabItem. This is because currently TabControl doesn't override PrepareContainerForItemOverride, so it won't automatically wrap your data source in TabItems.
public class TabConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
List<TabSource> source = value as List<TabSource>;
if (source != null)
{
List<TabItem> result = new List<TabItem>();
foreach (TabSource tab in source)
{
result.Add(new TabItem()
{
Header = tab.Header,
Content = tab.Content
});
}
return result;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}Now you can write this:
<UserControl.Resources>
<local:TabConverter x:Key="tc"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<y:TabControl x:Name="tab" ItemsSource="{Binding Converter={StaticResource tc}}"/>
</Grid>List<TabSource> source = new List<TabSource>();
source.Add(new TabSource()
{
Header = "a",
Content = new Button() { Content = "First Tab" }
});
source.Add(new TabSource()
{
Header = new TextBox() { Text = "b" },
Content = new CheckBox() { Content = "Second Tab" }
});
tab.DataContext = source;Note this won't auto select the first tab. You need to manually select it, or modify the Converter, so the first TabItem is selected.
-
Wednesday, June 18, 2008 1:06 AM
Thanks. This solved the issue. With this approach, is there a way to create a DataTemplate through C#?
-
Friday, June 20, 2008 2:36 AM
Unfortunately no. DataTemplate is designed to be created in XAML. Unless you use XamlReader, there's no way to create DataTemplate in code. A better approach is to create the DataTemplate in XAML in UserControl.Resources section, and access it in code. Then you can assign the template to anything you want.
-
Friday, June 20, 2008 5:18 PMHow can we access the UserControl.Resources in C#? I did find a workaround by manually coding the children objects into the tab control, but it would be nice to use the DataTemplate.
-
Sunday, June 22, 2008 11:57 PM
Suppose you have defined a DataTemplate with x:Key="dt" in the UserControl.Resources section. In code, you can write something like this:
DataTemplate dt = (DataTemplate)this.Resources["dt"];
Then you an assign this DataTemplate to anything you want.
-
Tuesday, July 29, 2008 1:49 PM
From your earlier example:
Content = new CheckBox() { Content = "Second Tab" }Question is, I want to have a ListBox in the Tab Content, what should I do? I did something like this:
Content = new ListBox() { ItemsSource = tab.myList }
But how can I assign DataTemplate to it (binding to the elements of "myList")? And is this the best way to do it? Since I am planning to have multiple items and a few layers in the Content. (e.g. several other titles + tabs under each tab, then ListBox under second tab layer) Seems like I am messing up something here...o.O
-
Sunday, January 25, 2009 5:26 AM
If I have a class of tabSource:
public class TabSource { public object header { get; set; } public object content { get; set; } }
And converter:
public class TabConverter : IValueConverter { public object Convert(object value, Type TargetType, object parameter, System.Globalization.CultureInfo culture) { List zdroj = value as List; if (zdroj != null) { List vysledek = new List(); foreach (TabSource ts in zdroj) { vysledek.Add(new TabItem() { Header = ts.header, Content = ts.content }); } return vysledek; } return null; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
XAML
<UserControl.Resources> <projekt:TabConverter x:Key="Converter"/> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <basics:TabControl x:Name="tc_auta" ItemsSource="{Binding Converter={StaticResource Convert}}"/> </Grid>
and Page.xaml.cs
List zdroj = new List(); zdroj.Add(new TabSource() { header = "string", content = new TextBlock() { Text = "ahoj" } }); zdroj.Add(new TabSource() { header = "ping", content = new TextBlock() { Text = "ahoj" } }); tc_auta.DataContext = zdroj;
tc_auta.DataContext = zdroj; throw me en exception -->
Unable to cast object of type 'TabControl.TabSource' to type 'System.Windows.Controls.TabItem'.
I do not understand why. Does anybody know where could be a problem?
Thanks for answer.
-
Monday, August 24, 2009 7:30 PM
So, this is a more interest question here. How would I go about extending the TabControl to override the PrepareContainerForItemOverride myself? That is, until Silverlight implements it in the future. How do we program this to automatically wrap our data source in TabItems? I want to see an example here, because this is *exactly* what I'm trying to do today at work.currently TabControl doesn't override PrepareContainerForItemOverride, so it won't automatically wrap your data source in TabItems.
-
Thursday, February 11, 2010 6:59 AM
I have a problem can you please solve that. I have trying to create Dynamic TAB control from XMLfile (Tab control source). Here I am giving all my code as follows.
MainPage.xaml :
----------------------------
1 <UserControl x:Class="SampleDynamicTabControl.MainPage" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:y="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" 7 xmlns:local="clr-namespace:SampleDynamicTabControl" 8 xmlns:UCViews="clr-namespace:SampleDynamicTabControl.Views" 9 xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" 10 mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480" 11 Loaded="UserControl_Loaded"> 12 <!--<UserControl.Resources> 13 <local:TabConverter x:Key="tc"/> 14 </UserControl.Resources>--> 15 16 17 <Grid x:Name="LayoutRoot" Margin="10"> 18 <Grid.Resources> 19 <local:TabCollectionList x:Key="nl"/> 20 </Grid.Resources> 21 22 <!--<y:TabControl x:Name="tab" ItemsSource="{Binding Converter={StaticResource tc}}"/>--> 23 24 <local:MyTabControl Name="tc1" MyItemsSource="{Binding Converter={StaticResource nl}"> 25 <local:MyTabControl.TabItemTemplate> 26 <DataTemplate> 27 <StackPanel> 28 <navigation:Frame Name="cf1" Source="{Binding TabFrameUri}"/> 29 <!--<Button Content="{Binding TabFrameUri}"/>--> 30 31 </StackPanel> 32 </DataTemplate> 33 </local:MyTabControl.TabItemTemplate> 34 35 <local:MyTabControl.TabHeaderItemTemplate> 36 <DataTemplate> 37 <TextBlock Text="{Binding Title}"/> 38 </DataTemplate> 39 </local:MyTabControl.TabHeaderItemTemplate> 40 </local:MyTabControl> 41 </Grid> 42 43 </UserControl>
MyTabControl.cs:
---------------------------------
1 using System; 2 using System.Net; 3 using System.Windows; 4 using System.Windows.Controls; 5 using System.Windows.Documents; 6 using System.Windows.Ink; 7 using System.Windows.Input; 8 using System.Windows.Media; 9 using System.Windows.Media.Animation; 10 using System.Windows.Shapes; 11 using System.Collections; 12 13 namespace SampleDynamicTabControl 14 { 15 public class MyTabControl : TabControl 16 { 17 public MyTabControl() 18 : base() 19 { 20 } 21 22 public DataTemplate TabHeaderItemTemplate 23 { 24 get { return (DataTemplate)GetValue(TabHeaderItemTemplateProperty); } 25 set { SetValue(TabHeaderItemTemplateProperty, value); } 26 } 27 public static readonly DependencyProperty TabHeaderItemTemplateProperty = 28 DependencyProperty.Register("TabHeaderItemTemplate", typeof(DataTemplate), typeof(MyTabControl), new PropertyMetadata( 29 (sender, e) => 30 { 31 ((MyTabControl)sender).InitTabs(); 32 })); 33 34 public DataTemplate TabItemTemplate 35 { 36 get { return (DataTemplate)GetValue(TabItemTemplateProperty); } 37 set { SetValue(TabItemTemplateProperty, value); } 38 } 39 public static readonly DependencyProperty TabItemTemplateProperty = 40 DependencyProperty.Register("TabItemTemplate", typeof(DataTemplate), typeof(MyTabControl), new PropertyMetadata( 41 (sender, e) => 42 { 43 ((MyTabControl)sender).InitTabs(); 44 })); 45 46 public IList MyItemsSource 47 { 48 get { return (IList)GetValue(MyItemsSourceProperty); } 49 set { SetValue(MyItemsSourceProperty, value); } 50 } 51 public static readonly DependencyProperty MyItemsSourceProperty = 52 DependencyProperty.Register("MyItemsSource", typeof(IList), typeof(MyTabControl), new PropertyMetadata( 53 (sender, e) => 54 { 55 ((MyTabControl)sender).InitTabs(); 56 })); 57 58 internal void InitTabs() 59 { 60 Items.Clear(); 61 if (MyItemsSource != null) 62 { 63 for (int i = 0; i < MyItemsSource.Count; i++) 64 { 65 var newTabItem = new TabItem(); 66 67 68 if (TabHeaderItemTemplate != null) 69 newTabItem.Header = TabHeaderItemTemplate.LoadContent(); 70 71 if (TabItemTemplate != null) 72 newTabItem.Content = TabItemTemplate.LoadContent(); 73 74 newTabItem.DataContext = MyItemsSource
;
75 Items.Add(newTabItem);
76 }
77 }
78 }
79 }
80 }
81
EntityDefine.cs:
-------------------------------
1 using System; 2 using System.Net; 3 using System.Windows; 4 using System.Windows.Controls; 5 using System.Windows.Documents; 6 using System.Windows.Ink; 7 using System.Windows.Input; 8 using System.Windows.Media; 9 using System.Windows.Media.Animation; 10 using System.Windows.Shapes; 11 using System.Collections.Generic; 12 using System.Xml; 13 14 namespace SampleDynamicTabControl 15 { 16 public class Tabs 17 { 18 public string Title { set; get; } 19 public string TabFrameUri { set; get; } 20 } 21 22 public class TabCollectionList : List<Tabs> 23 { 24 public TabCollectionList() 25 : base() 26 { 27 28 string strHeader; 29 string strFrameUri; 30 XmlReader reader = XmlReader.Create("TabData.xml"); 31 reader.MoveToContent(); 32 33 while (reader.Read()) 34 { 35 if (reader.NodeType == XmlNodeType.Element && reader.Name == "TabItem") 36 { 37 strHeader = reader.GetAttribute("header"); 38 strFrameUri = reader.GetAttribute("TargetFormUri"); 39 Add(new Tabs 40 { 41 Title = strHeader, 42 TabFrameUri = strFrameUri, 43 }); 44 } 45 46 if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "TabCollection") 47 { 48 break; 49 } 50 } 51 reader.Close(); 52 } 53 } 54 } 55
here i am got the path like "/Views/ContentPage1.xaml" from XML file but all 3 Tabs I am getting same XAML file (loaded in navigation:Frame Source=""). But some times i am getting to XAMLs shell know the reson behind that.Please reply me ASAP or send to my personal mail ID
-
Monday, February 22, 2010 11:02 AMIf you are doing MVVM please replace this: ItemsSource="{Binding Converter={StaticResource tc}}" With this: ItemsSource="{Binding source, Converter={StaticResource tc}}" and remove tab.DataContext = source;
-
Wednesday, February 24, 2010 6:27 AM
Thanks for your previous reply. I have a problem with my tab control. Can you please solve this -
1. I am having 30 tab items.
2. I need a tab left right buttons which are to scroll left or right to the tab items.
3. and a menu which is having all list of tab items and if I click on that I just go to particular tab click.
Please solve my problem.
-
Thursday, May 06, 2010 11:18 AM
Well Ashok you can keep all the tab object in a List or Dictionary and try to show only few tabs, let's say 5 tabs and keep replacing them from the List when you click left or right.Thanks for your previous reply. I have a problem with my tab control. Can you please solve this -
1. I am having 30 tab items.
2. I need a tab left right buttons which are to scroll left or right to the tab items.
3. and a menu which is having all list of tab items and if I click on that I just go to particular tab click.
Please solve my problem. My personal mail ID: ashok.just4u@gmail.com

