Adding TabItem dynamically when custom HeaderTemplate

7 posts, 1 answers
  1. elena petrova
    elena petrova avatar
    14 posts
    Member since:
    Oct 2009

    Posted 19 May 2010 Link to this post

    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
  2. Kiril Stanoev
    Admin
    Kiril Stanoev avatar
    1511 posts

    Posted 20 May 2010 Link to this post

    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.
  3. DevCraft banner
  4. elena petrova
    elena petrova avatar
    14 posts
    Member since:
    Oct 2009

    Posted 20 May 2010 Link to this post

    Thanks for help!
  5. elena petrova
    elena petrova avatar
    14 posts
    Member since:
    Oct 2009

    Posted 20 May 2010 Link to this post

    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


  6. elena petrova
    elena petrova avatar
    14 posts
    Member since:
    Oct 2009

    Posted 21 May 2010 Link to this post

    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
  7. Answer
    Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 25 May 2010 Link to this post

    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.
  8. elena petrova
    elena petrova avatar
    14 posts
    Member since:
    Oct 2009

    Posted 26 May 2010 Link to this post

    Yes that works for me. Thanks a lot!
Back to Top
DevCraft banner