WPF下可编辑Header的Tab控件实现

简介:

介绍

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

 

 

代码

首先,我们需要给Tab Header设计一个ControlTemplate。类似一个TextBlock,双击进入编辑状态。 所以Xaml如下:

 


 
 
  1. <Setter Property="Template"> 
  2.                 <Setter.Value> 
  3.                     <ControlTemplate TargetType="{x:Type local:EditableTabHeaderControl}"> 
  4.                         <Grid> 
  5.                             <TextBox x:Name="PART_TabHeader" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content, Mode=TwoWay}" Visibility="Collapsed"/> 
  6.                             <TextBlock x:Name="PART_TextBlock" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content, Mode=TwoWay}"/> 
  7.                         </Grid> 
  8.                         <ControlTemplate.Triggers> 
  9.                             <Trigger Property="IsInEditMode" Value="True"> 
  10.                                 <Trigger.Setters> 
  11.                                     <Setter TargetName="PART_TabHeader" Property="Visibility" Value="Visible"/> 
  12.                                     <Setter TargetName="PART_TextBlock" Property="Visibility" Value="Collapsed"/> 
  13.                                 </Trigger.Setters> 
  14.                             </Trigger> 
  15.                         </ControlTemplate.Triggers> 
  16.              </ControlTemplate> 
  17.         </Setter.Value> 
  18. </Setter> 

 

接下来,我们需要定义个“EditableTabHeaderControl”类,它具有控制TextBox和TextBlock的能力。如下:

 


 
 
  1. namespace EditableTabHeaderDemo 
  2.     using System; 
  3.     using System.Windows; 
  4.     using System.Windows.Controls; 
  5.     using System.Windows.Input; 
  6.     using System.Windows.Threading; 
  7.  
  8.     /// <summary> 
  9.     /// Header Editable TabItem 
  10.     /// </summary> 
  11.     [TemplatePart(Name = "PART_TabHeader"Type = typeof(TextBox))] 
  12.     public class EditableTabHeaderControl : ContentControl 
  13.     { 
  14.         /// <summary> 
  15.         /// Dependency property to bind EditMode with XAML Trigger 
  16.         /// </summary> 
  17.         private static readonly DependencyProperty IsInEditModeProperty = DependencyProperty.Register("IsInEditMode", typeof(bool), typeof(EditableTabHeaderControl)); 
  18.         private TextBox textBox; 
  19.         private string oldText; 
  20.         private DispatcherTimer timer; 
  21.         private delegate void FocusTextBox(); 
  22.  
  23.         /// <summary> 
  24.         /// Gets or sets a value indicating whether this instance is in edit mode. 
  25.         /// </summary> 
  26.         public bool IsInEditMode 
  27.         { 
  28.             get 
  29.             { 
  30.                 return (bool)this.GetValue(IsInEditModeProperty); 
  31.             } 
  32.             set 
  33.             {    
  34.                 if (string.IsNullOrEmpty(this.textBox.Text)) 
  35.                 { 
  36.                     thisthis.textBox.Text = this.oldText; 
  37.                 } 
  38.                  
  39.                 thisthis.oldText = this.textBox.Text; 
  40.                 this.SetValue(IsInEditModeProperty, value); 
  41.             } 
  42.         } 
  43.  
  44.         /// <summary> 
  45.         /// When overridden in a derived class, is invoked whenever application code or internal processes call <see cref="M:System.Windows.FrameworkElement.ApplyTemplate"/>
  46.         /// </summary> 
  47.         public override void OnApplyTemplate() 
  48.         { 
  49.             base.OnApplyTemplate(); 
  50.             thisthis.textBox = this.Template.FindName("PART_TabHeader", this) as TextBox; 
  51.             if (this.textBox != null) 
  52.             { 
  53.                 this.timer = new DispatcherTimer(); 
  54.                 this.timer.Tick += TimerTick; 
  55.                 this.timer.Interval = TimeSpan.FromMilliseconds(1); 
  56.                 this.LostFocus += TextBoxLostFocus; 
  57.                 this.textBox.KeyDown += TextBoxKeyDown; 
  58.                 this.MouseDoubleClick += EditableTabHeaderControlMouseDoubleClick; 
  59.             } 
  60.         } 
  61.  
  62.         /// <summary> 
  63.         /// Sets the IsInEdit mode. 
  64.         /// </summary> 
  65.         /// <param name="value">if set to <c>true</c> [value].</param> 
  66.         public void SetEditMode(bool value) 
  67.         { 
  68.             this.IsInEditMode = value
  69.             this.timer.Start(); 
  70.         } 
  71.  
  72.         private void TimerTick(object sender, EventArgs e) 
  73.         { 
  74.             this.timer.Stop(); 
  75.             this.MoveTextBoxInFocus(); 
  76.         } 
  77.  
  78.         private void MoveTextBoxInFocus() 
  79.         { 
  80.             if (this.textBox.CheckAccess()) 
  81.             { 
  82.                 if (!string.IsNullOrEmpty(this.textBox.Text)) 
  83.                 { 
  84.                     this.textBox.CaretIndex = 0
  85.                     this.textBox.Focus(); 
  86.                 } 
  87.             } 
  88.             else 
  89.             { 
  90.                 this.textBox.Dispatcher.BeginInvoke(DispatcherPriority.Render, new FocusTextBox(this.MoveTextBoxInFocus)); 
  91.             } 
  92.         } 
  93.  
  94.         private void TextBoxKeyDown(object sender, KeyEventArgs e) 
  95.         { 
  96.             if (e.Key == Key.Escape) 
  97.             { 
  98.                 this.textBox.Text = oldText
  99.                 this.IsInEditMode = false
  100.             } 
  101.             else if (e.Key == Key.Enter) 
  102.             { 
  103.                 this.IsInEditMode = false
  104.             } 
  105.         } 
  106.  
  107.         private void TextBoxLostFocus(object sender, RoutedEventArgs e) 
  108.         { 
  109.             this.IsInEditMode = false
  110.         } 
  111.  
  112.         private void EditableTabHeaderControlMouseDoubleClick(object sender, MouseButtonEventArgs e) 
  113.         { 
  114.             if (e.LeftButton == MouseButtonState.Pressed) 
  115.             { 
  116.                 this.SetEditMode(true); 
  117.             } 
  118.         } 
  119.     } 
  120. }    

这里有一个问题,当控件进入编辑状态,TextBox变为可见状态时,它不能自动获得focus。一种解决办法是挂一个Timer,每1毫秒轮询一次,检查状态并控制focus。

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

 


 
 
  1. <Window x:Class="EditableTabHeaderDemo.MainWindow" 
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4.     xmlns:local="clr-namespace:EditableTabHeaderDemo" 
  5.     Title="EditableTabHeaderDemo" Height="300" Width="500"> 
  6.     <Window.Resources> 
  7.         <Style x:Key="EditableTabHeaderControl" TargetType="{x:Type local:EditableTabHeaderControl}"> 
  8.             <!-- The template specified earlier will come here !--> 
  9.         </Style> 
  10.         <Style x:Key="ItemContainerStyle" TargetType="TabItem"> 
  11.             <Setter Property="HeaderTemplate"> 
  12.                 <Setter.Value> 
  13.                     <DataTemplate> 
  14.                         <local:EditableTabHeaderControl 
  15.                    Style="{StaticResource EditableTabHeaderControl}"> 
  16.                             <local:EditableTabHeaderControl.Content> 
  17.                                 <Binding Path="Name" Mode="TwoWay"/> 
  18.                             </local:EditableTabHeaderControl.Content> 
  19.                         </local:EditableTabHeaderControl> 
  20.                     </DataTemplate> 
  21.                 </Setter.Value> 
  22.             </Setter> 
  23.         </Style> 
  24.         <DataTemplate x:Key="ContentTemplate"> 
  25.             <Grid> 
  26.                 <TextBlock HorizontalAlignment="Left" Text="{Binding Name}"/> 
  27.                 <TextBlock HorizontalAlignment="Center" Text="{Binding City}"/> 
  28.             </Grid> 
  29.         </DataTemplate> 
  30.     </Window.Resources> 
  31.     <Grid> 
  32.         <TabControl Grid.Row="0" ItemsSource="{Binding Data}" ItemContainerStyle="{StaticResource ItemContainerStyle}" ContentTemplate="{StaticResource ContentTemplate}" /> 
  33.     </Grid> 
  34. </Window> 

 

许可证

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

源码下载

EditableTabHeaderSolution.zip



本文转自 powertoolsteam 51CTO博客,原文链接:http://blog.51cto.com/powertoolsteam/469126,如需转载请自行联系原作者

相关文章
|
6月前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
378 0
|
6月前
|
C#
浅谈WPF之装饰器实现控件锚点
使用过visio的都知道,在绘制流程图时,当选择或鼠标移动到控件时,都会在控件的四周出现锚点,以便于修改大小,移动位置,或连接线等,那此功能是如何实现的呢?在WPF开发中,想要在控件四周实现锚点,可以通过装饰器来实现,今天通过一个简单的小例子,简述如何在WPF开发中,应用装饰器,仅供学习分享使用,如有不足之处,还请指正。
137 1
|
3月前
|
开发框架 缓存 前端开发
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
|
3月前
|
C# 开发者 Windows
一款基于Fluent设计风格、现代化的WPF UI控件库
一款基于Fluent设计风格、现代化的WPF UI控件库
|
3月前
|
开发框架 前端开发 JavaScript
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(10) -- 在DataGrid上直接编辑保存数据
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(10) -- 在DataGrid上直接编辑保存数据
|
3月前
|
C# Windows
WPF中如何使用HandyCotrol控件库
WPF中如何使用HandyCotrol控件库
184 1
|
3月前
|
C# 开发者 Windows
WPF与PDF文档:解锁创建和编辑PDF文件的新技能——从环境配置到代码实践,手把手教你如何在WPF应用中高效处理PDF,提升文档管理效率
【8月更文挑战第31天】随着数字文档的普及,PDF因跨平台兼容性和高保真度成为重要格式。WPF虽不直接支持PDF处理,但借助第三方库(如iTextSharp)可在WPF应用中实现PDF的创建与编辑。本文通过具体案例和示例代码,详细介绍了如何在WPF中集成PDF库,并展示了从设计用户界面到实现PDF创建与编辑的完整流程。不仅包括创建新文档的基本步骤,还涉及在现有PDF中添加页眉页脚等高级功能。通过这些示例,WPF开发者可以更好地掌握PDF处理技术,提升应用程序的功能性和实用性。
134 0
|
3月前
|
C# 开发者 数据处理
WPF开发者必备秘籍:深度解析数据网格最佳实践,轻松玩转数据展示与编辑大揭秘!
【8月更文挑战第31天】数据网格控件是WPF应用程序中展示和编辑数据的关键组件,提供排序、筛选等功能,显著提升用户体验。本文探讨WPF中数据网格的最佳实践,通过DevExpress DataGrid示例介绍其集成方法,包括添加引用、定义数据模型及XAML配置。通过遵循数据绑定、性能优化、自定义列等最佳实践,可大幅提升数据处理效率和用户体验。
61 0
|
3月前
|
C# 前端开发 UED
WPF数据验证实战:内置控件与自定义规则,带你玩转前端数据验证,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,数据验证是确保输入正确性的关键环节。前端验证能及时发现错误,提升用户体验和程序可靠性。本文对比了几种常用的WPF数据验证方法,并通过示例展示了如何使用内置验证控件(如`TextBox`)及自定义验证规则实现有效验证。内置控件结合`Validation`类可快速实现简单验证;自定义规则则提供了更灵活的复杂逻辑支持。希望本文能帮助开发者更好地进行WPF数据验证。
106 0
|
3月前
|
C# UED 定位技术
WPF控件大全:初学者必读,掌握控件使用技巧,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,控件是实现用户界面交互的关键元素。WPF提供了丰富的控件库,包括基础控件(如`Button`、`TextBox`)、布局控件(如`StackPanel`、`Grid`)、数据绑定控件(如`ListBox`、`DataGrid`)等。本文将介绍这些控件的基本分类及使用技巧,并通过示例代码展示如何在项目中应用。合理选择控件并利用布局控件和数据绑定功能,可以提升用户体验和程序性能。
62 0