This is a migrated thread and some comments may be shown as answers.

Adding TabItem dynamically when custom HeaderTemplate

6 Answers 231 Views
TabControl
This is a migrated thread and some comments may be shown as answers.
elena petrova
Top achievements
Rank 1
elena petrova asked on 19 May 2010, 05:06 PM
Hi!
I have tabcontrol with custom Header and Content Templates
 <telerik:RadTabControl x:Name="tabControl" Align="Left" SelectedIndex="0"
            <telerik:RadTabControl.ItemContainerStyle> 
                <Style TargetType="telerik:RadTabItem"
                    <Setter Property="HeaderTemplate"
                        <Setter.Value> 
                            <DataTemplate> 
                                    <TextBlock Text="{Binding Name}" 
                                               FontSize="11" 
                                               Margin="5 0 5 0" 
                                               VerticalAlignment="Center" /> 
                            </DataTemplate> 
                        </Setter.Value> 
                    </Setter> 
                    <Setter Property="ContentTemplate"
                        <Setter.Value> 
                            <DataTemplate> 
                                <Grid HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20"
                                    <panels:RadUniformGrid Columns="2"
                                        <TextBlock Text="Name:" /> 
                                        <TextBox Text="{Binding Name, Mode=TwoWay}" Width="200"/> 
                                        <TextBlock Text="Date of Birth:  " /> 
                                        <input:RadDatePicker SelectedDate="{Binding DateOfBirth, Mode=TwoWay}" /> 
                                        <TextBlock Text="Address:" /> 
                                        <TextBox Text="{Binding Address, Mode=TwoWay}" Width="200"/> 
                                    </panels:RadUniformGrid> 
                                </Grid> 
                            </DataTemplate> 
                        </Setter.Value> 
                    </Setter> 
                </Style> 
            </telerik:RadTabControl.ItemContainerStyle> 
        </telerik:RadTabControl> 
In the MainPage.xaml.cs I have
 public Page() 
        { 
            InitializeComponent(); 
           Loaded += new RoutedEventHandler(Page_Loaded); 
        } 
 
        void Page_Loaded(object sender, RoutedEventArgs e) 
        { 
            tabControl.ItemsSource = new List<Person>() 
            { 
                new Person() 
                { 
                    Name = "Joe Cryton"
                    Address = "4 Park Lane av. "
                    DateOfBirth = new DateTime(1978, 5, 12) 
 
                }, 
 
                new Person() 
                { 
                    Name = "Denis Lawson"
                    Address = "12 Woodgrave str"
                    DateOfBirth = new DateTime(1980, 12, 1) 
 
                }, 
 
                new Person() 
                { 
                    Name = "Miles Rush"
                    Address = "7 Lake str."
                    DateOfBirth = new DateTime(1985, 1, 20) 
 
                } 
            }; 
        } 
 
        private void Button_Click(object sender, RoutedEventArgs e) 
        { 
            Person p = new Person() 
                           { 
                               Name = "Joe Cryton"
                               Address = "4 Park Lane av. "
                               DateOfBirth = new DateTime(1978, 5, 12) 
 
                           }; 
                                 
            tabControl.Items.Add(p); 
        } 
 
 
    } 
 
    public class Person:INotifyPropertyChanged 
    { 
         
        private String address; 
        /// <summary> 
        /// Gets or sets address of the person. 
        /// </summary> 
        public String Address 
        { 
            get 
            { 
                return this.address; 
            } 
            set 
            { 
                if (this.address != value) 
                { 
                    this.address = value
                    OnPropertyChanged("Address"); 
                } 
            } 
        } 
         
        private DateTime? dateOfBirth; 
        /// <summary> 
        /// Gets or sets the day of birth of the person. 
        /// </summary> 
        public DateTime? DateOfBirth 
        { 
            get 
            { 
                return this.dateOfBirth; 
            } 
            set 
            { 
                if (this.dateOfBirth != value) 
                { 
                    this.dateOfBirth = value
                    OnPropertyChanged("DateOfBirth"); 
                } 
            } 
        } 
 
        private String name; 
        /// <summary> 
        /// Gets or sets name of the person. 
        /// </summary> 
        public String Name 
        { 
            get 
            { 
                return this.name; 
            } 
            set 
            { 
                if (this.name != value) 
                { 
                    this.name = value
                    OnPropertyChanged("Name"); 
                } 
            } 
        } 
 
        /// <summary> 
        ///     Called when the value of a property changes. 
        /// </summary> 
        /// <param name="propertyName">The name of the property that has changed.</param> 
        protected virtual void OnPropertyChanged(String propertyName) 
        { 
            if (String.IsNullOrEmpty(propertyName)) 
            { 
                return; 
            } 
            if (PropertyChanged != null) 
            { 
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
            } 
        } 
 
        /// <summary> 
        ///     Raised when the value of one of the properties changes. 
        /// </summary> 
        public event PropertyChangedEventHandler PropertyChanged; 
    } 
The error occurs when I try to add tabControl.Items.Add(new Person()..)
Is it not correct?
Please advice me the correct solution.
Thanks in advance.
Elena

6 Answers, 1 is accepted

Sort by
0
Kiril Stanoev
Telerik team
answered on 20 May 2010, 02:26 PM
Hi Elena,

There are couple of things you need to modify in you project in order to run properly. First, instead of binding RadTabControl to a List<Person> you have to bind it to an ObservableCollection<Person>. The advantage of ObservableCollection over List is that ObservableCollection notifies the control when there is a change in its items i.e. RadTabControl will be notified when adding or removing items from the collection.

void Page_Loaded(object sender, RoutedEventArgs e)
{
    tabControl.ItemsSource = new ObservableCollection<Person>()
    {
        new Person() { ... },
        new Person() { ... },
        new Person() { ... }
            
    };
}

Second, when an ItemsControl (RadTabControl in this case) is bound i.e. you are using its ItemsSource property, it is not a good practice to modify its Items collection since this causes exceptions. Therefore, instead of:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Person p = new Person() { ... };
 
    tabControl.Items.Add(p);
}


you have to do:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Person p = new Person() { ... };
 
    (tabControl.ItemsSource as ObservableCollection<Person>).Add(p);
}

Give it a try and let me know how it goes. I'd be glad to further assist you.

All the best,
Kiril Stanoev
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
elena petrova
Top achievements
Rank 1
answered on 20 May 2010, 04:24 PM
Thanks for help!
0
elena petrova
Top achievements
Rank 1
answered on 20 May 2010, 04:52 PM
Hi again!
Now I have another problem.
I have overrided ItemsPanelTemplate - I am using PathPanel. And I have created PathRadTabItem which I have inhereted from RadTabItem and which implements IPathLayoutItem interface.
I have tried to  use ItemContainerStyle
<Grid x:Name="LayoutRoot" Background="White"
        <telerik:RadTabControl x:Name="tabControl" BorderBrush="#FF8D8484" BorderThickness="1,0,1,1" Style="{StaticResource TabControlStyle}"
            <telerik:RadTabControl.ItemsPanel> 
                <ItemsPanelTemplate> 
                    <ec:PathPanel Height="100" Margin="20"
                        <ec:PathPanel.LayoutPaths> 
                            <ec:LayoutPath SourceElement="{Binding ElementName=path}" Orientation="OrientToPath"/> 
                        </ec:PathPanel.LayoutPaths> 
                    </ec:PathPanel> 
                </ItemsPanelTemplate> 
            </telerik:RadTabControl.ItemsPanel> 
            <telerik:RadTabControl.ItemContainerStyle> 
                <Style TargetType="Controls:PathRadTabItem"
                    <Setter Property="HeaderTemplate"
                        <Setter.Value> 
                            <DataTemplate> 
                                <TextBlock Text="{Binding Name}"  
                                               FontSize="11"  
                                               Margin="5 0 5 0"  
                                               VerticalAlignment="Center" /> 
                            </DataTemplate> 
                        </Setter.Value> 
                    </Setter> 
                    <Setter Property="ContentTemplate"
                        <Setter.Value> 
                            <DataTemplate> 
                                <Grid HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20"
                                    <panels:RadUniformGrid Columns="2"
                                        <TextBlock Text="Name:" /> 
                                        <TextBox Text="{Binding Name, Mode=TwoWay}" Width="200"/> 
                                        <TextBlock Text="Date of Birth:  " /> 
                                        <telerik:RadDatePicker SelectedDate="{Binding DateOfBirth, Mode=TwoWay}" /> 
                                        <TextBlock Text="Address:" /> 
                                        <TextBox Text="{Binding Address, Mode=TwoWay}" Width="200"/> 
                                    </panels:RadUniformGrid> 
                                </Grid> 
                            </DataTemplate> 
                        </Setter.Value> 
                    </Setter> 
                </Style> 
            </telerik:RadTabControl.ItemContainerStyle> 
        </telerik:RadTabControl> 
        <Ellipse x:Name="path" Opacity="0" Margin="0,0,10,20" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" Stroke="Black" StrokeThickness="1" StrokeMiterLimit="10" StrokeLineJoin="Miter" Height="393" Width="720"/> 
        <Ellipse x:Name="path_Copy" Margin="50,20,57,46" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" Stroke="#ECE8DB" StrokeThickness="2" StrokeMiterLimit="10" StrokeLineJoin="Miter" Height="360"/> 
        <Ellipse x:Name="path_Copy1" Margin="35,-13,43,76" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" Stroke="#ECE8DB" StrokeThickness="4" StrokeMiterLimit="10" StrokeLineJoin="Miter" Height="360"/> 
    </Grid>

But I get xaml parser error.
 
The code for PathRadTabItem
public class PathRadTabItem : RadTabItem, IPathLayoutItem 
    { 
        public static readonly DependencyProperty GlobalIndexProperty = DependencyProperty.Register("GlobalIndex", typeof(int), typeof(PathRadTabItem), new PropertyMetadata(0)); 
        public static readonly DependencyProperty GlobalOffsetProperty = DependencyProperty.Register("GlobalOffset", typeof(double), typeof(PathRadTabItem), new PropertyMetadata(0.0)); 
        public static readonly DependencyProperty LayoutPathIndexProperty = DependencyProperty.Register("LayoutPathIndex", typeof(int), typeof(PathRadTabItem), new PropertyMetadata(0)); 
        public static readonly DependencyProperty LocalIndexProperty = DependencyProperty.Register("LocalIndex", typeof(int), typeof(PathRadTabItem), new PropertyMetadata(0)); 
        public static readonly DependencyProperty LocalOffsetProperty = DependencyProperty.Register("LocalOffset", typeof(double), typeof(PathRadTabItem), new PropertyMetadata(0.0)); 
        public static readonly DependencyProperty NormalAngleProperty = DependencyProperty.Register("NormalAngle", typeof(double), typeof(PathRadTabItem), new PropertyMetadata(0.0)); 
        public static readonly DependencyProperty OrientationAngleProperty = DependencyProperty.Register("OrientationAngle", typeof(double), typeof(PathRadTabItem), new PropertyMetadata(0.0)); 
        public event EventHandler<PathLayoutUpdatedEventArgs> PathLayoutUpdated; 
 
 
        public PathRadTabItem() 
        { 
            DefaultStyleKey = typeof(PathRadTabItem); 
        } 
 
        public int GlobalIndex 
        { 
            get 
            { 
                return (int)GetValue(GlobalIndexProperty); 
            } 
            internal set 
            { 
                SetValue(GlobalIndexProperty, value); 
            } 
        } 
 
        public double GlobalOffset 
        { 
            get 
            { 
                return (double)GetValue(GlobalOffsetProperty); 
            } 
            internal set 
            { 
                SetValue(GlobalOffsetProperty, value); 
            } 
        } 
 
        public int LayoutPathIndex 
        { 
            get 
            { 
                return (int)GetValue(LayoutPathIndexProperty); 
            } 
            internal set 
            { 
                SetValue(LayoutPathIndexProperty, value); 
            } 
        } 
 
        public int LocalIndex 
        { 
            get 
            { 
                return (int)GetValue(LocalIndexProperty); 
            } 
            internal set 
            { 
                SetValue(LocalIndexProperty, value); 
            } 
        } 
 
        public double LocalOffset 
        { 
            get 
            { 
                return (double)GetValue(LocalOffsetProperty); 
            } 
            internal set 
            { 
                SetValue(LocalOffsetProperty, value); 
            } 
        } 
 
        public double NormalAngle 
        { 
            get 
            { 
                return (double)GetValue(NormalAngleProperty); 
            } 
            internal set 
            { 
                SetValue(NormalAngleProperty, value); 
            } 
        } 
 
        public double OrientationAngle 
        { 
            get 
            { 
                return (double)GetValue(OrientationAngleProperty); 
            } 
            internal set 
            { 
                SetValue(OrientationAngleProperty, value); 
            } 
        } 
 
 
 
        public void Update(PathLayoutData data) 
        { 
            ChangedPathLayoutProperties none = ChangedPathLayoutProperties.None; 
            if (this.LayoutPathIndex != data.LayoutPathIndex) 
            { 
                none |= ChangedPathLayoutProperties.LayoutPathIndex; 
                this.LayoutPathIndex = data.LayoutPathIndex; 
            } 
            if (this.GlobalIndex != data.GlobalIndex) 
            { 
                none |= ChangedPathLayoutProperties.GlobalIndex; 
                this.GlobalIndex = data.GlobalIndex; 
            } 
            if (this.LocalIndex != data.LocalIndex) 
            { 
                none |= ChangedPathLayoutProperties.LocalIndex; 
                this.LocalIndex = data.LocalIndex; 
            } 
            if (this.GlobalOffset != data.GlobalOffset) 
            { 
                none |= ChangedPathLayoutProperties.GlobalOffset; 
                this.GlobalOffset = data.GlobalOffset; 
            } 
            if (this.LocalOffset != data.LocalOffset) 
            { 
                none |= ChangedPathLayoutProperties.LocalOffset; 
                this.LocalOffset = data.LocalOffset; 
            } 
            if (this.NormalAngle != data.NormalAngle) 
            { 
                none |= ChangedPathLayoutProperties.NormalAngle; 
                this.NormalAngle = data.NormalAngle; 
            } 
            if (this.OrientationAngle != data.OrientationAngle) 
            { 
                none |= ChangedPathLayoutProperties.OrientationAngle; 
                this.OrientationAngle = data.OrientationAngle; 
            } 
            this.OnPathLayoutUpdated(new PathLayoutUpdatedEventArgs(none)); 
        } 
 
        void OnPathLayoutUpdated(PathLayoutUpdatedEventArgs pathLayoutArgs) 
        { 
            if (PathLayoutUpdated != null) 
            { 
                PathLayoutUpdated(this, pathLayoutArgs); 
            } 
        } 
    } 
And its template
<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Telerik_Windows_Controls_Primitives1="clr-namespace:Telerik.Windows.Controls.Primitives;assembly=Telerik.Windows.Controls.Navigation" xmlns:SilverlightApplication1="clr-namespace:SilverlightApplication1.Controls"
    <ControlTemplate x:Key="TabItemTemplate" TargetType="SilverlightApplication1:PathRadTabItem"
        <Grid x:Name="wrapper" RenderTransformOrigin="0.5,0.5"
            <Grid.RenderTransform> 
                <RotateTransform Angle="{Binding OrientationAngle, RelativeSource={RelativeSource TemplatedParent}}"/> 
            </Grid.RenderTransform> 
            <VisualStateManager.VisualStateGroups> 
                <VisualStateGroup x:Name="CommonStateGroup"
                    <VisualState x:Name="MouseOver"
                        <Storyboard> 
                            <ObjectAnimationUsingKeyFrames 
                                        Storyboard.TargetName="Bg" 
                                        Storyboard.TargetProperty="Opacity" 
                                        Duration="0"
                                <DiscreteObjectKeyFrame KeyTime="0" 
                                            Value="1" /> 
                            </ObjectAnimationUsingKeyFrames> 
 
                        </Storyboard> 
                    </VisualState> 
                    <VisualState x:Name="Normal" /> 
                    <VisualState x:Name="Selected"
                        <Storyboard> 
                            <ObjectAnimationUsingKeyFrames 
                                        Storyboard.TargetName="Bg" 
                                        Storyboard.TargetProperty="Opacity" 
                                        Duration="0"
                                <DiscreteObjectKeyFrame KeyTime="0" 
                                            Value="1" /> 
                            </ObjectAnimationUsingKeyFrames> 
                            <ObjectAnimationUsingKeyFrames 
                                        Storyboard.TargetName="Bg" 
                                        Storyboard.TargetProperty="BorderBrush" 
                                        Duration="0"
                                <DiscreteObjectKeyFrame KeyTime="0" 
                                            Value="#FF72C8D0" /> 
                            </ObjectAnimationUsingKeyFrames> 
                            <ObjectAnimationUsingKeyFrames 
                                        Storyboard.TargetName="Bg" 
                                        Storyboard.TargetProperty="Background" 
                                        Duration="0"
                                <DiscreteObjectKeyFrame KeyTime="0" 
                                            Value="#FFCED3D9" /> 
                            </ObjectAnimationUsingKeyFrames> 
                            <ObjectAnimationUsingKeyFrames 
                                        Storyboard.TargetName="wrapper" 
                                        Storyboard.TargetProperty="Margin" 
                                        Duration="0"
                                <DiscreteObjectKeyFrame KeyTime="0" 
                                            Value="0 0 0 -1" /> 
                            </ObjectAnimationUsingKeyFrames> 
                            <ObjectAnimationUsingKeyFrames 
                                        Storyboard.TargetName="HeaderElement" 
                                        Storyboard.TargetProperty="Foreground" 
                                        Duration="0"
                                <DiscreteObjectKeyFrame KeyTime="0" 
                                            Value="#FF000000" /> 
                            </ObjectAnimationUsingKeyFrames> 
                        </Storyboard> 
                    </VisualState> 
                    <VisualState x:Name="Disabled"
                        <Storyboard> 
                            <DoubleAnimation 
                                        Storyboard.TargetProperty="Opacity" 
                                        Storyboard.TargetName="HeaderElement" 
                                        To="0.5" Duration="0:0:0.1" /> 
                        </Storyboard> 
                    </VisualState> 
                </VisualStateGroup> 
                <VisualStateGroup x:Name="FocusStates"
                    <VisualState x:Name="Unfocused" /> 
                    <VisualState x:Name="Focused" /> 
                </VisualStateGroup> 
            </VisualStateManager.VisualStateGroups> 
 
            <Border x:Name="Bg" Margin="2 0"  
                        BorderBrush="#AFACA1" 
                        Background="#ECE8DB" 
                        BorderThickness="1,0,1,0" CornerRadius="3,3,0,0" /> 
 
            <Telerik_Windows_Controls_Primitives1:TabItemContentPresenter 
                        x:Name="HeaderElement" 
                        Content="{TemplateBinding Header}" 
                        HorizontalAlignment="Center" 
                        ContentTemplate="{TemplateBinding HeaderTemplate}" 
                        VerticalAlignment="Center" 
                        Foreground="{TemplateBinding Foreground}" 
                        Margin="{TemplateBinding Padding}" /> 
        </Grid> 
    </ControlTemplate> 
 
    <Style  TargetType="SilverlightApplication1:PathRadTabItem"
        <Setter Property="MinWidth" Value="118"/> 
        <!--<Setter Property="BorderThickness" Value="{StaticResource TabItem_OuterBorderThickness}"/>--> 
        <Setter Property="Foreground" Value="#65635D"/> 
        <Setter Property="MinHeight" Value="30"/> 
        <Setter Property="Background" Value="Transparent"/> 
        <Setter Property="BorderBrush" Value="Black"/> 
        <Setter Property="HorizontalContentAlignment" Value="Center"/> 
        <Setter Property="VerticalContentAlignment" Value="Center"/> 
        <Setter Property="Padding" Value="6 3"/> 
        <Setter Property="IsTabStop" Value="False"/> 
        <Setter Property="Template" Value="{StaticResource TabItemTemplate}"/> 
    </Style> 
     
    <Thickness x:Key="TabItem_OuterBorderThickness">1 1 1 1</Thickness> 
    <SolidColorBrush x:Key="ControlForeground_Normal" Color="#FF000000"/> 
    <SolidColorBrush x:Key="TabItem_Background_Normal" Color="Transparent"/> 
    <SolidColorBrush x:Key="TabItem_OuterBorder_Normal" Color="Black"/> 
 
 
    <LinearGradientBrush x:Key="TabBorder_Select" EndPoint="0.5,1" 
                StartPoint="0.5,0"
        <GradientStop Color="#FFA4A4A4" Offset="0" /> 
        <GradientStop Color="#FF72C8D0" Offset="1" /> 
    </LinearGradientBrush> 
 
    <LinearGradientBrush x:Key="TabBackground_Select" EndPoint="0.5,1" 
                StartPoint="0.5,0"
        <GradientStop Color="#FFF3F4F6" Offset="0" /> 
        <GradientStop Color="#FFCED3D9" Offset="1" /> 
    </LinearGradientBrush> 
 
</ResourceDictionary> 
Thanks in advance for your help.

Elena


0
elena petrova
Top achievements
Rank 1
answered on 21 May 2010, 01:17 PM
So if I have custom TabItem which inherits RadTabitem it is not possible to set in xaml HeaderTemplate and ContentTemplate in ItemContainerStyle? Or this ItemContainer expects only RadTabItem and I should override smth in RadTabControl.
Thanks
0
Accepted
Tina Stancheva
Telerik team
answered on 25 May 2010, 05:36 PM
Hello Elena Petrova,

You can use a custom TabItem deriving from RadTabItem, but you will also need to define a custom TabControl deriving from the RadTabControl and override the GetContainerForItemOverride() method to return a custom TabItem instead of RadTabItem.

Also, it is better to use the ItemTemplate and ContentTemplate properties of the RadTabControl to define the header and content templates of the items instead of using ItemContainerStyle.

I modified your code to illustrate the suggested approach. Take a look at the attached sample project and let me know if this is what you had in mind.


All the best,
Tina Stancheva
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
elena petrova
Top achievements
Rank 1
answered on 26 May 2010, 11:19 AM
Yes that works for me. Thanks a lot!
Tags
TabControl
Asked by
elena petrova
Top achievements
Rank 1
Answers by
Kiril Stanoev
Telerik team
elena petrova
Top achievements
Rank 1
Tina Stancheva
Telerik team
Share this question
or