65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 中的可编辑标题选项卡控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (11投票s)

2010年12月20日

CPOL

1分钟阅读

viewsIcon

66943

downloadIcon

1172

提供一个 ControlTemplate, 使选项卡标题可以编辑

HeaderEditableTabControl.png

介绍 

最近,我需要开发一个WPF中的选项卡控件,当用户双击选项卡标题时,标题变为可编辑状态。主要思路是为选项卡标题提供一个ControlTemplate,并在该模板上关联必要的触发器。

Using the Code

首先,我们需要设计选项卡标题的ControlTemplate。选项卡标题只是一个TextBlock,双击它会变成一个TextBox。因此,所需的XAML非常简单: 

<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>		

现在,我们需要提供一个类“EditableTabHeaderControl”,它将具有依赖属性和逻辑来控制textboxtextblock的可见性。 这是该类: 

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);
            }
        }
    }
}

当控件变为可编辑状态时,会出现一个问题。那就是,当textbox的可见性从折叠状态变为可见状态时,它不会自动获得焦点。为了实现这一点,我添加了一个定时器,该定时器在textbox变为可编辑状态后1毫秒触发,并将焦点移至该textbox。现在,我们准备好使用我们的可编辑标题模板了。我们将添加一个WPFTabControl,并为该控件提供ItemContainerStyle。然后,当我们双击标题时,它将变为可编辑状态。

<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>  

历史

  • 2010年12月20日:初始发布
© . All rights reserved.