zoukankan      html  css  js  c++  java
  • WPF下可编辑Header的Tab控件实现

    介绍

    有这样一个需求,当用户双击Tab控件Header区域时, 希望可以直接编辑。对于WPF控件,提供一个ControlTemplate在加上一些Trigger就可以实现。效果如下:

    代码

    首先,我们需要给Tab Header设计一个ControlTemplate。类似一个TextBlock,双击进入编辑状态。 所以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”类,它具有控制TextBox和TextBlock的能力。如下:

    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变为可见状态时,它不能自动获得focus。一种解决办法是挂一个Timer,每1毫秒轮询一次,检查状态并控制focus。

    现在就来添加一个WPF TabControl,并应用ItemContainerStyle。然后双击Header,可以编辑啦~

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

    开发工具

    ComponentOne Studio WPF 是专为桌面应用程序开发所准备的一整套控件包,崇尚优雅和创新,以“触控优先”为设计理念,内含轻量级高性能表格控件,和大量类型丰富的2D和3D图表控件,能使开发的应用程序更富创意。

    许可证

    本文以及示例代码文件遵循The Code Project Open License(CPOL)

    源码下载

    EditableTabHeaderSolution.zip

    英文链接:Header Editable Tab Control in Wpf



    本文是由葡萄城技术开发团队发布,转载请注明出处:葡萄城官网


  • 相关阅读:
    Java实现 LeetCode 394 字符串解码
    Java实现 LeetCode 394 字符串解码
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 390 消除游戏
    Java实现 LeetCode 390 消除游戏
  • 原文地址:https://www.cnblogs.com/powertoolsteam/p/1922370.html
Copyright © 2011-2022 走看看