Click here to Skip to main content
15,868,164 members
Articles / Desktop Programming / WPF

Header Editable Tab Control in WPF

Rate me:
Please Sign up or sign in to vote.
4.75/5 (11 votes)
20 Dec 2010CPOL1 min read 64.1K   1.1K   22   16
Providing a ControlTemplate so that the Tab Header can be editable
HeaderEditableTabControl.png

Introduction 

Recently, I needed to develop a Tab Control in WPF where the Tab Headers become editable while user double clicks on that. The main idea is to provide a ControlTemplate for the Tab Header and associate necessary Triggers on that.

Using the Code

At first, we need to design the ControlTemplate for the Tab Header. The Tab Header is simply a TextBlock, double clicking on it will turn it into a TextBox. So, the XAML required for this is very simple:  

XML
<Setter Property="Template">
    <Setter.Value>
          <ControlTemplate TargetType="{x:Type local:EditableTabHeaderControl}">
              <Grid>
                  <TextBox x:Name="PART_TabHeader" Text="{Binding RelativeSource=
		{RelativeSource TemplatedParent}, Path=Content, Mode=TwoWay}" 
		Visibility="Collapsed"/>
                  <TextBlock x:Name="PART_TextBlock" Text="{Binding RelativeSource=
		{RelativeSource TemplatedParent}, Path=Content, Mode=TwoWay}"/>
              </Grid>
          <ControlTemplate.Triggers>
                  <Trigger Property="IsInEditMode" Value="True">
                        <Trigger.Setters>
                            <Setter TargetName="PART_TabHeader" Property="Visibility" 
			Value="Visible"/>
                            <Setter TargetName="PART_TextBlock" Property="Visibility" 
			Value="Collapsed"/>
                        </Trigger.Setters>
                  </Trigger>
              </ControlTemplate.Triggers>
           </ControlTemplate>
    </Setter.Value>
</Setter>		

Now, we need to provide the class "EditableTabHeaderControl", which will have the dependency properties and logic to control the visibility of textbox. textblock pair. Here is the class:  

C#
namespace EditableTabHeaderDemo
{
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Threading;

    /// <summary>
    /// Header Editable TabItem
    /// </summary>
    [TemplatePart(Name = "PART_TabHeader", Type = typeof(TextBox))]
    public class EditableTabHeaderControl : ContentControl
    {
        /// <summary>
        /// Dependency property to bind EditMode with XAML Trigger
        /// </summary>
        private static readonly DependencyProperty IsInEditModeProperty = 
		DependencyProperty.Register("IsInEditMode", typeof(bool), 
		typeof(EditableTabHeaderControl));
        private TextBox textBox;
        private string oldText;
        private DispatcherTimer timer;
        private delegate void FocusTextBox();

        /// <summary>
        /// Gets or sets a value indicating whether this instance is in edit mode.
        /// </summary>
        public bool IsInEditMode
        {
            get
            {
                return (bool)this.GetValue(IsInEditModeProperty);
            }
            set
            {   
                if (string.IsNullOrEmpty(this.textBox.Text))
                {
                    this.textBox.Text = this.oldText;
                }
                
                this.oldText = this.textBox.Text;
                this.SetValue(IsInEditModeProperty, value);
            }
        }

        /// <summary>
        /// When overridden in a derived class, is invoked whenever 
        /// application code or internal processes call 
        /// <see cref="M:System.Windows.FrameworkElement.ApplyTemplate"/>.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.textBox = this.Template.FindName("PART_TabHeader", this) as TextBox;
            if (this.textBox != null)
            {
                this.timer = new DispatcherTimer();
                this.timer.Tick += TimerTick;
                this.timer.Interval = TimeSpan.FromMilliseconds(1);
                this.LostFocus += TextBoxLostFocus;
                this.textBox.KeyDown += TextBoxKeyDown;
                this.MouseDoubleClick += EditableTabHeaderControlMouseDoubleClick;
            }
        }

        /// <summary>
        /// Sets the IsInEdit mode.
        /// </summary>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public void SetEditMode(bool value)
        {
            this.IsInEditMode = value;
            this.timer.Start();
        }

        private void TimerTick(object sender, EventArgs e)
        {
            this.timer.Stop();
            this.MoveTextBoxInFocus();
        }

        private void MoveTextBoxInFocus()
        {
            if (this.textBox.CheckAccess())
            {
                if (!string.IsNullOrEmpty(this.textBox.Text))
                {
                    this.textBox.CaretIndex = 0;
                    this.textBox.Focus();
                }
            }
            else
            {
                this.textBox.Dispatcher.BeginInvoke
		(DispatcherPriority.Render, new FocusTextBox(this.MoveTextBoxInFocus));
            }
        }

        private void TextBoxKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                this.textBox.Text = oldText;
                this.IsInEditMode = false;
            }
            else if (e.Key == Key.Enter)
            {
                this.IsInEditMode = false;
            }
        }

        private void TextBoxLostFocus(object sender, RoutedEventArgs e)
        {
            this.IsInEditMode = false;
        }

        private void EditableTabHeaderControlMouseDoubleClick
		(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                this.SetEditMode(true);
            }
        }
    }
}

One problem arises when the control become editable. That is, when the visibility of the textbox turns to visible from collapsed, it does not get focus automatically. To achieve that, I have added a timer which fires after 1 millisecond of the textbox became editable and brings it to focus. Now, we are ready to use our Editable Header Template. We will add a WPF TabControl and provide ItemContainerStyle to the control. Then, when we double click the Header, it will be editable.

XML
<Window x:Class="EditableTabHeaderDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:EditableTabHeaderDemo"
    Title="EditableTabHeaderDemo" Height="300" Width="500">
    <Window.Resources>
        <Style x:Key="EditableTabHeaderControl" 
	TargetType="{x:Type local:EditableTabHeaderControl}">
			<!-- The template specified earlier will come here !-->
        </Style>
        <Style x:Key="ItemContainerStyle" TargetType="TabItem">
            <Setter Property="HeaderTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <local:EditableTabHeaderControl
                   Style="{StaticResource EditableTabHeaderControl}">
                            <local:EditableTabHeaderControl.Content>
                                <Binding Path="Name" Mode="TwoWay"/>
                            </local:EditableTabHeaderControl.Content>
                        </local:EditableTabHeaderControl>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <DataTemplate x:Key="ContentTemplate">
            <Grid>
                <TextBlock HorizontalAlignment="Left" Text="{Binding Name}"/>
                <TextBlock HorizontalAlignment="Center" Text="{Binding City}"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <TabControl Grid.Row="0" ItemsSource="{Binding Data}" 
	ItemContainerStyle="{StaticResource ItemContainerStyle}" 
	ContentTemplate="{StaticResource ContentTemplate}" />
    </Grid>
</Window>  

History

  • 20th December, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Student University of Alabama at Birmingham
United States United States

A very simple guy, who codes with his heart (and with his brain, of course).

Homepage: http://www.amitdutta.net
View my profile on Linkedin: http://www.linkedin.com/in/am1tdutta/

Comments and Discussions

 
QuestionBinding the text into my ViewModel Pin
Member 147053702-Jan-20 5:25
Member 147053702-Jan-20 5:25 
QuestionHow to trigger a renaming from outside the control? Pin
Tobias Walter17-Oct-11 21:56
Tobias Walter17-Oct-11 21:56 
AnswerRe: How to trigger a renaming from outside the control? Pin
Amit Kumar Dutta17-Oct-11 22:25
Amit Kumar Dutta17-Oct-11 22:25 
GeneralRe: How to trigger a renaming from outside the control? Pin
Member 123744398-Mar-16 22:12
Member 123744398-Mar-16 22:12 
GeneralMy vote of 5 Pin
prasad0222-Dec-10 3:42
prasad0222-Dec-10 3:42 
GeneralRe: My vote of 5 Pin
Amit Kumar Dutta22-Dec-10 5:44
Amit Kumar Dutta22-Dec-10 5:44 
QuestionData not persistance.... Pin
arithforu20-Dec-10 18:15
arithforu20-Dec-10 18:15 
AnswerRe: Data not persistance.... Pin
Amit Kumar Dutta20-Dec-10 18:45
Amit Kumar Dutta20-Dec-10 18:45 
GeneralMy vote of 5 Pin
SledgeHammer0120-Dec-10 5:22
SledgeHammer0120-Dec-10 5:22 
GeneralRe: My vote of 5 Pin
Amit Kumar Dutta22-Dec-10 15:56
Amit Kumar Dutta22-Dec-10 15:56 
Generalgood trick.. Pin
Sazzad Hossain20-Dec-10 3:57
Sazzad Hossain20-Dec-10 3:57 
GeneralRe: good trick.. Pin
Amit Kumar Dutta22-Dec-10 15:57
Amit Kumar Dutta22-Dec-10 15:57 
GeneralSuggestion Pin
Venkatesh Mookkan20-Dec-10 0:47
Venkatesh Mookkan20-Dec-10 0:47 
GeneralRe: Suggestion Pin
Amit Kumar Dutta20-Dec-10 18:54
Amit Kumar Dutta20-Dec-10 18:54 
GeneralMy vote of 5 Pin
jakaria_bd19-Dec-10 23:59
jakaria_bd19-Dec-10 23:59 
GeneralRe: My vote of 5 Pin
Amit Kumar Dutta22-Dec-10 15:58
Amit Kumar Dutta22-Dec-10 15:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.