Add Button To Tab

11 posts, 1 answers
  1. Peter
    Peter avatar
    22 posts
    Member since:
    Nov 2007

    Posted 07 Jun 2009 Link to this post

    Hi,
    I'm trying to add a close button to my tabs.  My tabs are being created dynamically in code-behind and then added to the TabControl.

     

     

    private void AddNewTab(object control, string header)  
    {              
        RadTabItem item = new RadTabItem();  
        item.Header = header;                          
        item.Content = control;  
     
        MainTabControl.Items.Add(item);  
        MainTabControl.SelectedItem = item;  


    I've gone through the examples I've found on here, but they all use databinding to create the tabs.
    Is there a way to add a button to the header using a DataTemplate and still get the header text to display properly?
    I've tried setting the RadTabItem's tag to the header and using the following DataTemplate, but I only get the close button to show.
            <DataTemplate x:Key="TabItemHeaderTemplate1">  
                <Grid> 
                    <Grid.ColumnDefinitions> 
                        <ColumnDefinition Width="*"/>  
                        <ColumnDefinition Width="Auto"/>  
                    </Grid.ColumnDefinitions>                  
                    <TextBlock Text="{TemplateBinding Tag}"/>  
                    <Button Grid.Column="1" Style="{StaticResource ImageButtonStyle}" business:EventHelper.EnableRoutedClick="True" ToolTipService.ToolTip="Close">  
                        <Button.Content> 
                            <Image Source="Icons/close_32.png" Height="20" Width="20"/>  
                        </Button.Content> 
                    </Button> 
                </Grid> 
            </DataTemplate> 
     


    Any help would be appreciated.

    -Pete
  2. Kiril Stanoev
    Admin
    Kiril Stanoev avatar
    1511 posts

    Posted 10 Jun 2009 Link to this post

    Hi Peter,
    Silverlight does not offer a way to register for an event in the DataTemplate of a control, so we have to come up with workarounds.

    On workaround is to add a UserControl in the template that will have a logic to notify when the button is clicked (i.e. the button will be in the UserControl and the UserControl will have access to the button and its properties.

    A more general solution will be to use RoutedEvents which will travel down the visual three and can be handled at a root object. The Telerik controls use Routed Events but unfortunately the default Button does not. Our implementation of the routed events is compatible with all controls, so you could attach a routed event to the button and fire it. Then you can handle the routed event and remove the item.

    You can find a sample project attached demonstrating this scenario.
    Please take a look at it and let us know how it works for you.

    Best wishes,
    Kiril Stanoev
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  3. DevCraft banner
  4. Peter
    Peter avatar
    22 posts
    Member since:
    Nov 2007

    Posted 10 Jun 2009 Link to this post

    Thanks for the example.

    While the code works, it's not quite what I'm looking for.  In your example, you create a few MyViewModel objects and attach them to the tabControls ItemsSource.  I'm creating RadTabItems from button clicks.  I'm looking for a way to use a DataTemplate for the Tab Header to put a button on it, while at the same time manually setting the header text when creating the RadTabItem.  (see my AddNewTab function in my previous post)  I've tried using your example by changing the MyViewModel class and making the Content property a UserControl, but when it's added to the tabControl it does not display properly.  Do you have an example that uses a UserControl for the Content instead of a Textbox in the ContentTemplate?

    Thanks
  5. Sandi
    Sandi avatar
    6 posts
    Member since:
    May 2009

    Posted 10 Jun 2009 Link to this post

    I would love to see a solution that demonstrates this as well.




  6. Answer
    Miroslav
    Admin
    Miroslav avatar
    922 posts

    Posted 11 Jun 2009 Link to this post

    Hello Sandi,

    You can define a DataTemplate in the resources (user control or application resources) and then get the DataTemplate from the resource dictionary when needed. I the previous example the header is a string, so we can create DataTemplate with a TextBlock and a button, then when creating the item we set the HeaderTemplate:

    var item = new RadTabItem();  
    item.Header = "Some String";  
    // The template we assign has a button that works with routed events.  
    item.HeaderTemplate = this.Resources["TemplateWithCloseButton"as DataTemplate; 

    If you are not happy with handling routed events, you can also build up the header element by element. IMO this is harder to maintain, but you can register for the close button Click event in code:

    // Alternatively we can add any object to the header, so we can  
    // build the header instead of using a template:  
    var panel = new StackPanel() { Orientation = Orientation.Horizontal };  
    panel.Children.Add(new TextBlock(){ Text = "Some String" });  
    var button = new Button() { Content = "x" };  
    button.Click += new RoutedEventHandler(OnClose);  
    panel.Children.Add(button); 

    Hopefully this is what you need,

    Kind regards,
    Miroslav
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  7. Srinivas
    Srinivas avatar
    48 posts
    Member since:
    May 2009

    Posted 09 Jul 2009 Link to this post

    Hi,

    I followed your suggestion to create Data Template and attach it to HeaderTemplate of the tab item but in my case the tab item header is set dynamically based on the option it was selected. How can I use binding in the Data Template? For example, in the code behind I am creating the entire tab control and tab items dynamically and when I create the tab item the header is set based on the option the user selected and I cannot hard-code the header in the Data Template. When I attach template it just displays the close button with no tab heading.

    Any help?

    Thanks
    Srinivas
  8. Miroslav
    Admin
    Miroslav avatar
    922 posts

    Posted 10 Jul 2009 Link to this post

    Hi Srinivas,

    The HeaderTemplate binds to whatever is in the Header of the item (same for Content and ContentTemplate).

    This means that if you want to bind a string, you can do something like:

    tabItem.Header = "My String"

    and then in the template you can have an element that binds to it:

    <TextBlock Text="{Binding}" />

    This is an empty path binding, i.e. it is bound directly to the header object. If you choose to set a custom object (ViewModel-like) you can bind to one of its properties as well.

    Also, if your TabItems are all dynamically created, you may want to consider binding the TabControl to an observable collection and then adding templates (or TemplateSelectors) for the headers and the content of the items. This way you will not have to manage adding/removing and creating TabItems in code.

    Hopefully this will help you,

    Regards,
    Miroslav
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  9. Srinivas
    Srinivas avatar
    48 posts
    Member since:
    May 2009

    Posted 26 Jul 2009 Link to this post

    Hello Miroslav,

    Do you have any simple sample to demonstrate adding/removing tab items dynamically as you explained below?

    Also, if I want to perform certain tasks when we switch tabs, for example if I switch from tab1 to tab2 I would like to perform some cleanup activities in tab1 before switching to tab2. Do you have any sample to demonstrate this?

    ----------
    Also, if your TabItems are all dynamically created, you may want to consider binding the TabControl to an observable collection and then adding templates (or TemplateSelectors) for the headers and the content of the items. This way you will not have to manage adding/removing and creating TabItems in code.
    ----------

    I really appreciate your help on this.

    Thanks
    Srinivas
  10. Miroslav
    Admin
    Miroslav avatar
    922 posts

    Posted 30 Jul 2009 Link to this post

    Hello Srinivas,

    I am sorry for the delayed reply.

    I am sending you a sample project where the TabControl is bound to a collection of items. The example is using an Observable collection which means that the TabItems will automatically be added/removed as you add/remove items from the collection.

    Also the example uses a TemplateSelectors for both the headers and the content of the TabItems. This can be simplified if you use a single template. Then it can be assigned as HeaderTemplate or ContentTemplate, without using selectors.

    Providing a collection for the ItemsSource makes more sense when the content of the TabItems is similar, but it can also be used otherwise.

    As for doing the cleanup - you can use the SelectionChanged event. There you have the items that have been unselected, you can access them and their content and do the cleanup you need.

    Hopefully this will be useful for you,

    Best wishes,
    Miroslav
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  11. Srinivas
    Srinivas avatar
    48 posts
    Member since:
    May 2009

    Posted 04 Aug 2009 Link to this post

    Hello Miroslav,

    Thank you very much for your time and exaple projects. As I am very new to Silverlight and no WPF background or any of similar kind, some of the code looks very complex to me to understand. Though I was able to follow most of it but still I am not able to modify the sample code to achieve my desired results. This is purely because I am very new to Silverlight and unable to understand some complex code.

    I am looking for a sample in very simple code. For example, please consider below class from your one of the sample code:

    public

     

    class MyViewModel

     

    {

     

    public String Title { get; set; }

     

     

    public String Content { get; set; }

     

    }

    In this class the Content is of String type but I would like to change this to an UserControl type so that I can assign new XAML pages as TabItem content. For example if I change the class to:

     

    public

     

    class MyViewModel

     

     

     

    {

     

     

    public String Title { get; set; }

     

     

    public UserControl  Content { get; set; }

     

    }

    and then change the assignment to:

     

    myViewModelCollection.Add(

    new MyViewModel()

     

    {

    Title = "User Profile"

    ,

     

    Content =

    new UserProfilePage();

     

    });

     

     

     

    where UserProfilePage is a XAML page within the same project. And when the user click on the "Close" button of the TabItem I would like to close the selected TabItem.

    I am not sure how to change the XAML page (from the same sample code that you provided) to achieve the result. Can you please suggest me a simple sample code to achieve the result?

    All I am trying to do is create TabItems dynamically, following your suggestion that is creating ObservableCollection as ItemSource for the TabControl and place XAML pages as contents for each TabItem (in my case it is based on Menu tree selection) and allow the user to close the tab.

    My Menu Tree:
    Option 1: UserProfilePage.XAML
    Option 2: UserAccountMaintenance.XAML
    Option 3: UserPasswordChange.XAML

    When Option 1 is selected then I would like to create a NEW TabItem (1st TabItem) and load UserProfilePage.XAML (Title: User Profile) and when Option 2 is selected then I would like to create a NEW TabItem (2nd TabItem) and load UserAccountMaintenance.XAML (Title: Account Maintenance) and when Option 3 is selected then I would like to create another NEW TabItem (3rd TabItem) and load UserPasswordChange.XAML (Title: Password Maintenance). At this point I have 3 TabItems open with 3 different XAML pages loaded. I would like to provide "Close" button or icon for each TabItem so that individual Tabs can be closed at any point.

    By default, I would like to create one TabItem and load HomePage.XAML as content and I do not want to provide "Close" button or icon for this default TabItem.

    I really appreciate your time and help on this.

    Thanks
    Srinivas

  12. Miroslav
    Admin
    Miroslav avatar
    922 posts

    Posted 09 Aug 2009 Link to this post

    Hi Srinivas,

    I am sorry for the delayed reply,

    There are a few things that are new as a convept in Silverlight, but I am sure that you will quickly find your way around.

    Sometimes in our examples we use the Model-View-ViewModel pattern (you can find a lot of examples and explanation for it online) but if you are just starting with Silverlight you may find it wasier to do more things in C# code, more like a WinForms application.

    Generally all ContentControls and ItemsControls accept objects as content, which means that you can put anything as the content of the TabItem (or any ItemsControls).

    An easy way to achieve what you need is to handle the SelectionChnaged event of the TreeView and create a new TabItem with the header and content (the UserControl) you need and then add it to the Items collection of the TabControl and then selected (set the SelectedItem property).

    The close button could be put as an overlay in the top right corner of the TabControl. Then you will need to handle its clicked event and remove the SelectedItem from the items collection.

    My example used an ObservableCollection and binding and you can (and should IMO) use this once you are more comfortable with Silverlight / WPF.

    Hopefully you will be able to achieve what you need.

    Greetings,
    Miroslav
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
Back to Top
DevCraft banner