本文阐述了如何在C#使自定义Windows选项卡控件。

介绍 

本文讨论如何使用.NET框架为windows窗体应用程序定制选项卡控件。示例应用程序在演示程序和源项目zip文件中可用。 

  • 记忆的支持  
  • 支持键盘导航  
  • 支持拖拽选项卡页面从一个容器转移到另一个标签改变也在同一个容器中
  • 添加标签页显示/隐藏下拉菜单的功能
  • 梯度选中的选项卡项及其背景
  • 彩色化支持控制标题(RGBA改变)
  • 支持终端用户的动态属性
  • 展示如何添加设计时支持你的自定义控件在设计时行为正当
  • 自定义msctls_updown32照片卷轴。 支持6种不同风格
  • 为KRBTabControl提供键盘支持用户操作
  • 支持透明背景的控制标题和选定的选项卡项目
  • 序列化支持(加载以前的设置或保存当前设置。)
  • 事件通知(图纸更改,更改下拉菜单,选项卡页面选择和关闭操作)

内容一目了然

不管怎样,我要在这篇文章如下:

类表

类提供了一个基本的控制基类的实现,但我们需要创建特定的类,属性,方法和事件对我们的控制。 要做到这一点,我已经实现了定制类。

在这里你可以检查类描述。

类名 描述
GradientTab 我们选中的选项卡项目矩形及其边界填充特定梯度通过使用这个类成员。 它包括几种绘图操作的属性。
GradientTabConverter
GradientTabEditor 支持缩略图,我们需要创建一个自定义类型编辑器。 类型编辑给你改变一点幻想通过创建一个自定义缩略图的梯度属性窗口。
GradientTabEditor 这个类,我们填选项卡页面头部区域的各种模式。 它包含四个属性为绘画操作。
HatcherConverter
HatcherEditor 属性在属性窗口。
HatchStyleConverter 标准的价值观。
CaptionGradient 您可以确定一个新的标题梯度风格选项卡控件通过使用这些类成员。
CaptionGradientConverter 成员。
CaptionGradientEditor 一个自定义类型编辑器类。 创建一个自定义缩略图的梯度属性窗口。
ButtonsCaption 你可以改变你的活跃或者不活跃的标题按钮的颜色通过使用这些类成员。
ButtonsCaptionConverter 成员。
ButtonsCaptionEditor 一个自定义类型编辑器类。 创建一个自定义缩略图的梯度属性窗口。
RandomizerCaption RGBA(红,绿,蓝和α)为控制标题再着色。 你可以很容易地改变你的标题出现通过使用这个类成员。
RandomizerCaptionConverter 财产。
CaptionColorChooserEditor
TabpageExCollectionEditor 在我们TabPages集合编辑器。
TabPageExPool 这个集合类包含我们的隐藏选项卡页面。 你在设计时不能隐藏选项卡页面。 它只在运行时工作模式。
Custom3DBorder 我们的分离器抽屉班。 它画一条垂直的线连接指定的两个点坐标对。
ArrowWindow 似乎只有当我们拖着一个标签项项目另一个选项卡。
UpDown32
Scroller 照片卷轴 控制。 你可以改变照片卷轴样式的属性对话框。
RolloverUpDown )。
UpDownBase 控制是声明为抽象类不能直接实例化。
KRBTabControlDesigner
KRBTabControlActionList 实例智能标记和当一个命令或改变,它执行相应的操作与控制。
TabPageEx 我们的自定义选项卡页面类。 我们需要改变和添加一些属性。
CaptionColorChooser 在标题更改RGBA值位图。 我们需要使用一个模态对话框改变颜色属性。
ContextMenuShownEventArgs 这门课是我们的下拉菜单项参数。
SelectedIndexChangingEventArgs 类。

控制边界样式

KRBTabControl边界样式
边框样式 预览
固体
虚线
Dashed

控制属性表

从我们的KRBTabControl几个属性。
财产 描述
  • TabStyles
获取或设置选中的选项卡页面风格。
  • BorderColor
获取或设置边框颜色的控制。
  • TabPageCloseIconColor
获取或设置图标的颜色选择选项卡。
  • TabHOffset
获取或设置距离像素,第一个选项卡页面的左边缘与容器的左边缘的客户区,该值必须在2至5像素大小的范围。
  • HeaderStyle
获取或设置的背景风格选项卡页眉。
  • TabGradient
获取或设置渐变颜色的选定的选项卡页项目。
  • GradientCaption
您可以确定一个新的选项卡控件标题梯度的风格和颜色。
  • CaptionButtons
你可以改变你的活跃或者不活跃的标题按钮的颜色。
  • CaptionRandomizer
你可以改变你的活跃的和不活跃的标题颜色组件(红,绿,蓝,α)。
  • UpDownStyle
获取或设置照片卷轴(上/下)选项卡控件的样式。
  • HeaderVisibility
确定活动选项卡是否延伸到它的父容器。
  • IsDrawHeader
决定是否选项卡标题背景画。
  • IsCaptionVisible
决定是否选项卡控件的标题是可见的。
  • IsDrawEdgeBorder
确定选项卡控件的边界是否画,你必须设置IsCaptionVisible的值为false此更改生效。
  • IsUserInteraction
向用户提供键盘支持选项卡控制操作。
  • IsDrawTabSeparator
确定标签之间的分隔线是否可见选项卡页面。
  • IsDocumentTabStyle
确定选项卡控件像文档标签样式。

选项卡页面风格

KRBTabControl选项卡页面风格
选项卡页面风格 预览
KRBStyle
OfficeXP
VS2010

控制事件

我实现了几个事件控制设计和最终用户通知。

KRBTabControl事件
事件名称 描述
  • DrawHeaderChanged
事件提出当IsDrawHeader属性的值改变。
  • CaptionVisibleChanged
事件提出当IsCaptionVisible属性的值改变。
  • StretchToParentChanged
事件引发的价值HeaderVisibility(StretchToParent)属性发生了改变。
  • TabPageClosing
发生在一个标签页面被关闭。
  • SelectedIndexChanging
发生在一个标签页面被选中。
  • ContextMenuShown
当用户点击下拉图标标题如果是可见的。

透明背景的支持

  预览
CaptionBar

TabPages

空集装箱

如果选项卡页面数小于1,你会看到一个空的容器标签如下。

透明背景支持tabpages和标题栏。

的ExpandableObjectConverter

自定义对象。

单独subproperties。

表示和扩大房地产看到subproperties的能力。

,如下所示:

class RandomizerCaptionConverter : ExpandableObjectConverter
{
    // To do something.
}

比后,我们使用覆盖所需的方法。

TypeConverter重写的方法
方法 描述
CanConvertFrom() 如果类型转换器可以从这个数据类型转换到自定义数据类型。
ConvertFrom() 此方法执行从所提供的数据类型转换到自定义数据类型。
CanConvertTo() 如果从自定义对象类型转换器可以转换数据类型。
ConvertTo() 这个方法执行自定义数据类型的转换请求的数据类型。
 1 #region Override Methods
 2 
 3 //所有的canconvertto()方法需要检查目标的类型是一个字符串。
 4 public override bool CanConvertTo
 5     (ITypeDescriptorContext context, Type destinationType)
 6 {
 7     if (destinationType == typeof(string))
 8         return true;
 9     else
10         return base.CanConvertTo(context, destinationType);
11 }
12 
13 //ConvertTo() simply checks that it can indeed convert to the desired type.
14 public override object ConvertTo(ITypeDescriptorContext context,
15     System.Globalization.CultureInfo culture, object value, Type destinationType)
16 {
17     if (destinationType == typeof(string))
18         return ToString(value);
19     else
20         return base.ConvertTo(context, culture, value, destinationType);
21 }
22 
23 /* 完全相同的过程发生在相反的过程中。
24 将对象转换为字符串时randomizercaption。
25 第一个属性窗口调用canconvertfrom()。
26 如果返回true,则下一步是调用
27  convertfrom()方法。 */
28 public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
29 {
30     if (sourceType == typeof(string))
31         return true;
32     else
33         return base.CanConvertFrom(context, sourceType);
34 }
35 
36 public override object ConvertFrom(ITypeDescriptorContext context,
37     System.Globalization.CultureInfo culture, object value)
38 {
39     if (value is string)
40         return FromString(value);
41     else
42         return base.ConvertFrom(context, culture, value);
43 }
44 
45 #endregion

 

附加一个类型转换器

属性类声明。

1 [TypeConverter(typeof(RandomizerCaptionConverter))]
2 public class RandomizerCaption : ICaptionRandomizer
3 { ... }

 

您的自定义属性的属性控制。

 1 /// <summary>
 2 /// You can change your active and inactive caption color components 
 3 /// (Red, Green, Blue, Alpha).
 4 /// </summary>
 5 [Description("You can change your active and inactive caption color components (Red, Green, Blue, Alpha)")]
 6 [TypeConverter(typeof(RandomizerCaptionConverter))]
 7 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
 8 [Browsable(true)]
 9 public RandomizerCaption CaptionRandomizer
10 {
11     get { return _captionRandomizer; }
12     set
13     {
14         try
15         {
16             if (!value.Equals(_captionRandomizer))
17             {
18                 _captionRandomizer.CaptionRandomizerChanged -= 
19                     CONTROL_INVALIDATE_UPDATE;
20                 _captionRandomizer = value;
21                 _captionRandomizer.CaptionRandomizerChanged +=
22                     new EventHandler(CONTROL_INVALIDATE_UPDATE);
23 
24                 Invalidate();
25                 Update();
26             }
27         }
28         catch (NullReferenceException)
29         {
30             MessageBox.Show("Value cannot be null!, please enter a valid value.");
31         }
32     }
33 }

 

编辑RandomizerCaption类的属性。

的UITypeEditor

名称空间。 您可以从这个类继承来创建您的自定义类型编辑器。

属性类声明或声明一个属性。

。 然后您可以覆盖以下表所示的四种方法。

UITypeEditor重写的方法:
ClassMethod 描述
EditValue() 当调用属性编辑。 一般来说,在这里您将创建一个特殊的对话框属性编辑。
GetEditStyle() (没有编辑支持)。
GetPaintValueSupported() 实现。
PaintValue() 画一个图形调用缩略图表示属性窗口中的值。

模态类型编辑器

模态类型编辑器显示了属性值旁边的省略号(…)按钮。 单击此按钮时,出现一个对话框,允许开发人员改变属性值。

CaptionColorChooser

内部类声明的关键字。

internal partial class CaptionColorChooser : Form
{
    // To do something.
}

真正的诀窍在本例中,您创建的模态形式编辑属性需要一种方法来接收信息的自定义控件对象。 要做到这一点,你应该创建一些公共实例编辑控制接收所需的所有信息。

存储instance-supplied信息的详细信息:

#region Instance Members

public KRBTabControl contextInstance;
public ICaptionRandomizer Randomizer;

#endregion

值可以改变用户在模态对话框。 所以我们需要为每个NumericUpDown控制创建一个事件处理程序,然后我们应该更新当前视图的形式。

private void numeric_ValueChanged(object sender, EventArgs e)
{
    // Update current view on the control.
    Captions.Invalidate();
    Captions.Update();
}

下一步是开发类型编辑器,使用该模态形式。 类声明的是:

class CaptionColorChooserEditor : UITypeEditor
{
    // To do something.
}

属性。

[Editor(typeof(CaptionColorChooserEditor), typeof(UITypeEditor))]
public class RandomizerCaption : ICaptionRandomizer
{ ... }

形式,设置初始属性的使用范围,如下所示:

 1 #region Override Methods
 2 
 3 public override object EditValue
 4 (ITypeDescriptorContext context, IServiceProvider provider, object value)
 5 {
 6     ICaptionRandomizer current;
 7     using (CaptionColorChooser frm = new CaptionColorChooser())
 8     {
 9         // Set currently objects to the form.
10         frm.Randomizer = (ICaptionRandomizer)value;
11         frm.contextInstance = context.Instance as KRBTabControl;
12 
13         if (frm.ShowDialog() == DialogResult.OK)
14             current = frm.Randomizer;
15         else
16             current = (ICaptionRandomizer)value;
17     }
18 
19     return current;
20 }
21 
22 public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
23 {
24     // We will use a window for property editing.
25     return UITypeEditorEditStyle.Modal;
26 }
27 
28 public override bool GetPaintValueSupported(ITypeDescriptorContext context)
29 {
30     // No special thumbnail will be shown for the grid.
31     return false;
32 }
33 
34 #endregion

 

在屏幕上显示了CaptionColorChooser对话框形式。

画一个缩略图

类:

#region Override Methods

public override bool GetPaintValueSupported(ITypeDescriptorContext context)
{
    return true;
}

public override void PaintValue(PaintValueEventArgs e)
{
    GradientTab gradient = e.Value as GradientTab;
    using (LinearGradientBrush brush = new LinearGradientBrush(e.Bounds, gradient.ColorStart, 
        gradient.ColorEnd, gradient.GradientStyle))
    {
        e.Graphics.FillRectangle(brush, e.Bounds);
    }
}

#endregion

 

RGBA再着色

接口。

 1 public interface ICaptionRandomizer : IDisposable
 2 {
 3     /// <summary>
 4     /// Determines whether the randomizer effect is enable or not for tab control caption.
 5     /// </summary>
 6     bool IsRandomizerEnabled { get; set; }
 7 
 8     /// <summary>
 9     /// Determines whether the transparency effect is visible or not 
10     /// for tab control caption.
11     /// </summary>
12     bool IsTransparencyEnabled { get; set; }
13 
14     /// <summary>
15     /// Gets or Sets, the red color component value of the caption bitmap.
16     /// </summary>
17     byte Red { get; set; }
18 
19     /// <summary>
20     /// Gets or Sets, the green color component value of the caption bitmap.
21     /// </summary>
22     byte Green { get; set; }
23 
24     /// <summary>
25     /// Gets or Sets, the blue color component value of the caption bitmap.
26     /// </summary>
27     byte Blue { get; set; }
28 
29     /// <summary>
30     /// Gets or Sets, the alpha color component value of the caption bitmap.
31     /// </summary>
32     byte Transparency { get; set; }
33 }

 

篇文章。 你可以操作你的标题栏外观如果它是可见的,如下面所示的例子:

颜色转换
操作色表——在不活跃的模式
默认的
增加了红色
增加了绿色
增加了蓝色

快捷键

如果启用了IsUserInteraction财产,提供用户键盘支持选项卡控件操作。

键盘按键
描述
结束 选择最后一个选项卡页面容器。
选择第一个选项卡页面容器。
选择选项卡左边当前选中的标签页的容器。
正确的 选择标签右侧的当前选中的标签页的容器。
插入 当用户按“插入”键,一个问题对话框,允许开发者插入一个新标签页。 如以下图片所示;

删除 从容器中删除选中的标签页。 这个键被按下时,出现一个对话框,允许开发人员从容器中删除当前选中选项卡页面如下所示。

的KRBTabControlDesigner

控制设计师允许您管理设计时行为和设计时界面(属性和事件)暴露你的控制。 虽然控制设计相当复杂的Windows窗体的基础设施,不难定制现有的控制设计添加新特性。

你可以得到一个定制的控制设计师使用与您的自定义控件。 你为什么要创建自己的设计师?

  • )。
  • 在一个空面板)。
  • )。

将为所有实例重用相同的设计师。) 一旦建立连接,控制设计师有能力参与开发人员之间的交互和控制。

。 下面的代码片段显示了如何创建一个控制设计师为你控制。

public class KRBTabControlDesigner : System.Windows.Forms.Design.ParentControlDesigner
{
    // To do something.
}

控制:

[Designer(typeof(KRBTabControlDesigner))]
public partial class KRBTabControl : TabControl
{ ... }

。 下面的表中列出了这些方法。

IDesignerFilter方法
方法 描述
PostFilterAttributes 重写这个方法来删除未使用的或不适当的属性。
PostFilterEvents 重写这个方法来删除未使用的或不适当的事件。
PostFilterProperties 重写这个方法来删除未使用的或不适当的属性。
PreFilterAttributes 重写这个方法添加属性。
PreFilterEvents 重写这个方法添加事件。
PreFilterProperties 重写这个方法添加属性。

来确定设计时环境中可用。

这里有一个例子,删除不适当的属性中指定以下代码转储。

protected override void PostFilterProperties
	(System.Collections.IDictionary properties)
{
    properties.Remove("Margin");
    properties.Remove("ImeMode");
    properties.Remove("Padding");
    properties.Remove("Enabled");
    properties.Remove("RightToLeft");
    properties.Remove("RightToLeftLayout");
    properties.Remove("ApplicationSettings");
    properties.Remove("DataBindings");

    base.PostFilterProperties(properties);
}

重要提示 

动态属性

在相同的方法。 下面的代码片段显示了如何应用这种行为你的自定义控件。

  1 /// <summary>
  2 /// Override this method to add some properties 
  3 /// to the control or change the properties attributes for a dynamic user interface.
  4 /// </summary>
  5 /// <param name="properties">Properties collection of the control
  6 /// before than add a new property to the collection by user.</param>
  7 protected override void PreFilterProperties(System.Collections.IDictionary properties)
  8 {
  9     base.PreFilterProperties(properties);
 10 
 11     // We don't want to show the "Location" and "ShowToolTips" properties for our control at the design-time.
 12     properties["Location"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 13       (PropertyDescriptor)properties["Location"], BrowsableAttribute.No);
 14     properties["ShowToolTips"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 15       (PropertyDescriptor)properties["ShowToolTips"], BrowsableAttribute.No);
 16 
 17     /* After than, we don't want to see some properties at design-time for general reasons
 18       (Dynamic property attributes). */
 19     KRBTabControl parentControl = Control as KRBTabControl;
 20 
 21     if (parentControl != null)
 22     {
 23         if (parentControl.HeaderVisibility)
 24         {
 25             properties["ItemSize"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 26               (PropertyDescriptor)properties["ItemSize"], BrowsableAttribute.No);
 27             properties["TabStyles"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 28               (PropertyDescriptor)properties["TabStyles"], BrowsableAttribute.No);
 29             properties["Alignments"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 30               (PropertyDescriptor)properties["Alignments"], BrowsableAttribute.No);
 31             properties["UpDownStyle"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 32               (PropertyDescriptor)properties["UpDownStyle"], BrowsableAttribute.No);
 33             properties["HeaderStyle"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 34               (PropertyDescriptor)properties["HeaderStyle"], BrowsableAttribute.No);
 35             properties["TabGradient"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 36               (PropertyDescriptor)properties["TabGradient"], BrowsableAttribute.No);
 37             properties["IsDrawHeader"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 38               (PropertyDescriptor)properties["IsDrawHeader"], BrowsableAttribute.No);
 39             properties["CaptionButtons"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 40               (PropertyDescriptor)properties["CaptionButtons"], BrowsableAttribute.No);
 41             properties["TabBorderColor"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 42               (PropertyDescriptor)properties["TabBorderColor"], BrowsableAttribute.No);
 43             properties["GradientCaption"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 44               (PropertyDescriptor)properties["GradientCaption"], BrowsableAttribute.No);
 45             properties["BackgroundColor"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 46               (PropertyDescriptor)properties["BackgroundColor"], BrowsableAttribute.No);
 47             properties["BackgroundImage"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 48               (PropertyDescriptor)properties["BackgroundImage"], BrowsableAttribute.No);
 49             properties["BackgroundHatcher"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 50               (PropertyDescriptor)properties["BackgroundHatcher"], BrowsableAttribute.No);
 51             properties["CaptionRandomizer"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 52               (PropertyDescriptor)properties["CaptionRandomizer"], BrowsableAttribute.No);
 53             properties["IsDrawTabSeparator"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 54               (PropertyDescriptor)properties["IsDrawTabSeparator"], BrowsableAttribute.No);
 55 
 56             return;
 57         }
 58 
 59         if (!parentControl.IsCaptionVisible)
 60         {
 61             properties["CaptionButtons"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 62                 (PropertyDescriptor)properties["CaptionButtons"], BrowsableAttribute.No);
 63             properties["CaptionRandomizer"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 64                 (PropertyDescriptor)properties["CaptionRandomizer"], BrowsableAttribute.No);
 65             properties["GradientCaption"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 66                 (PropertyDescriptor)properties["GradientCaption"], BrowsableAttribute.No);
 67         }
 68 
 69         if (parentControl.IsDrawHeader)
 70         {
 71             switch (parentControl.HeaderStyle)
 72             {
 73                 case KRBTabControl.TabHeaderStyle.Hatch:
 74                     properties["BackgroundColor"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 75                       (PropertyDescriptor)properties["BackgroundColor"], BrowsableAttribute.No);
 76                     properties["BackgroundImage"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 77                       (PropertyDescriptor)properties["BackgroundImage"], BrowsableAttribute.No);
 78                     break;
 79                 case KRBTabControl.TabHeaderStyle.Solid:
 80                     properties["BackgroundImage"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 81                       (PropertyDescriptor)properties["BackgroundImage"], BrowsableAttribute.No);
 82                     properties["BackgroundHatcher"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 83                       (PropertyDescriptor)properties["BackgroundHatcher"], BrowsableAttribute.No);
 84                     break;
 85                 default:
 86                     properties["BackgroundColor"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 87                       (PropertyDescriptor)properties["BackgroundColor"], BrowsableAttribute.No);
 88                     properties["BackgroundHatcher"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 89                       (PropertyDescriptor)properties["BackgroundHatcher"], BrowsableAttribute.No);
 90                     break;
 91             }
 92         }
 93         else
 94         {
 95             properties["HeaderStyle"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 96               (PropertyDescriptor)properties["HeaderStyle"], BrowsableAttribute.No);
 97             properties["BackgroundColor"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
 98               (PropertyDescriptor)properties["BackgroundColor"], BrowsableAttribute.No);
 99             properties["BackgroundImage"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
100               (PropertyDescriptor)properties["BackgroundImage"], BrowsableAttribute.No);
101             properties["BackgroundHatcher"] = TypeDescriptor.CreateProperty(typeof(KRBTabControl),
102               (PropertyDescriptor)properties["BackgroundHatcher"], BrowsableAttribute.No);
103         }
104     }
105 }

 

在您的自定义控件类属性。 下面的代码片段显示了如何将这个属性添加到您合适的属性声明和指定适当的标识符类型。

[RefreshProperties(RefreshProperties.All)]
public TabHeaderStyle HeaderStyle
{ get; set; }

最终用户属性。

智能标记

最新版本的Visual Studio包含一个新特性来创建丰富的设计时experience-smart标签。 智能标记的弹出窗口出现在控制当你点击旁边的小箭头。

,等等。 他们还可以包含静态的描述性文本。 通过这种方式,智能标记可以像一个迷你属性窗口。

属性。

一个示例智能标记窗口

要创建这个智能标记,需要以下材料:

  • DesignerActionItem对象的集合 代表一个单项智能标记。
  • 一个动作列表类 实例的智能标记,当一个命令或改变,它执行相应的操作与控制。
  • 一个控制设计 :此钩你的动作列表控制的智能标记出现在设计时。

动作列表

)。

名称空间)。

:

public class KRBTabControlActionList : DesignerActionList
{
    // To do something.
}

属性提供了访问控制。 然而,通过使用这种方法,您将获得便利的强类型访问控制。

#region Constructor

// The constructor associates the control to the smart tag action list.
public KRBTabControlActionList(KRBTabControl control)
    : base(control)
{
    _linkedControl = control;
    _host = (IDesignerHost)GetService(typeof(IDesignerHost));
    _changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService));
    _designerService = (DesignerActionUIService)GetService(typeof(DesignerActionUIService));

    // When this control will be added to the design area, the smart tag panel will open automatically.
    this.AutoShow = true;
}

#endregion

它们出现的顺序。

,然后返回集合。 根据你的智能标记的复杂性,这可能需要几个步骤。

第一步是创建一个标题,将智能标记划分为单独的区域。 然后您可以将其他物品添加到这些类别,如下所示:

 1 public override DesignerActionItemCollection GetSortedActionItems()
 2 {
 3     DesignerActionItemCollection items = new DesignerActionItemCollection();
 4     try
 5     {
 6         // Creating the action list static headers.
 7         items.Add(new DesignerActionHeaderItem("Commands"));
 8         items.Add(new DesignerActionHeaderItem("Appearance"));
 9 
10         if (!_linkedControl.HeaderVisibility)
11         {
12             // Creates other action list headers.
13             items.Add(new DesignerActionHeaderItem("Tab Item Appearance"));
14 
15             items.Add(new DesignerActionPropertyItem("TabStyles", "Tab Styles", "Appearance",
16                  "Tab Style"));
17 
18             items.Add(new DesignerActionPropertyItem("Alignments", "Tab Alignments", "Appearance",
19                 "Tab Alignment"));
20 
21             items.Add(new DesignerActionPropertyItem("FirstColor", "First Color", "Tab Item Appearance",
22                 "First TabItem Color"));
23 
24             items.Add(new DesignerActionPropertyItem("SecondColor", "Second Color", "Tab Item Appearance",
25                 "Second TabItem Color"));
26 
27             items.Add(new DesignerActionPropertyItem("GradientMode", "Gradient Mode", "Tab Item Appearance",
28                 "Gradient Style"));
29 
30             items.Add(new DesignerActionPropertyItem("IsSupportedAlphaColor", "Support Alpha Color", 
31                 "Tab Item Appearance", "Supports alpha component for tab item background colors"));
32 
33             items.Add(new DesignerActionMethodItem(this,
34                 "RandomizeColors", "Randomize Colors", "Tab Item Appearance",
35                 "Randomize TabItem Colors", false));
36         }
37 
38         items.Add(new DesignerActionMethodItem(this,
39             "HeaderVisibility", "StretchToParent " + (_linkedControl.HeaderVisibility ? "ON" : "OFF"), 
40             "Appearance", "Determines whether the active tab is stretched to its parent container or not", 
41              false));
42 
43         items.Add(new DesignerActionMethodItem(this,
44             "AddTab", "Add Tab", "Commands",
45             "Add a new tab page to the container", false));
46 
47         if (_linkedControl.TabCount > 0)
48         {
49             DesignerActionMethodItem methodRemove = new DesignerActionMethodItem(this, "RemoveTab", 
50             "Remove Tab", "Commands", "Removes the selected tab page from the container", false);
51 
52             items.Add(methodRemove);
53         }
54 
55         // Add a new static header and its items.
56         items.Add(new DesignerActionHeaderItem("Information"));
57         items.Add(new DesignerActionTextItem("X: " + _linkedControl.Location.X + ", " + "Y: " 
58         + _linkedControl.Location.Y, "Information"));
59         items.Add(new DesignerActionTextItem("Width: " + _linkedControl.Size.Width + ", " + "Height: " 
60         + _linkedControl.Size.Height, "Information"));
61     }
62     catch (Exception ex)
63     {
64         MessageBox.Show("Exception while generating the action list panel for this KRBTabControl, " + 
65         ex.Message);
66     }
67 
68     return items;
69 }

 

私有成员变量来优化性能。

public override DesignerActionListCollection ActionLists
{
    get
    {
        if (_actionLists == null)
        {
            _actionLists = new DesignerActionListCollection();
            _actionLists.Add(new KRBTabControlActionList((KRBTabControl)Control));
        }

        return _actionLists;
    }
}

拖放支持

如果启用AllowDrop属性,您可以拖动当前选中选项卡页面在其他选项卡页面。 而且你可以拖拽选项卡页面标签容器从一个到另一个地方。

选项卡标题样式

KRBTabControl标题样式
标题样式 预览
固体
孵化
纹理

下拉菜单定制

为菜单定制方法。

#region Customize ContextMenuStrip

private void krbTabControl1_ContextMenuShown(object sender, ContextMenuShownEventArgs e)
{
    ToolStripMenuItem menuItem = new ToolStripMenuItem()
    {
        Text = "Another menu item",
        ShortcutKeys = Keys.Control | Keys.N
    };

    menuItem.Click += (thrower, ea) =>
    {
        MessageBox.Show("Hello World!!!");
    };

    e.ContextMenu.Items.Insert(0, new ToolStripSeparator());
    e.ContextMenu.Items.Insert(0, menuItem);

    menuItem = new ToolStripMenuItem()
    {
        Text = "Open a new tab",
        Image = this.ımageList1.Images[2],
        ShortcutKeys = Keys.Control | Keys.O
    };

    menuItem.Click += (thrower, ea) =>
    {
        KRBTabControl.TabPageEx newTabPage = new KRBTabControl.TabPageEx();
        newTabPage.ImageIndex = 2;
        krbTabControl1.TabPages.Add(newTabPage);
        Label newLabel = new Label();
        newLabel.AutoSize = true;
        newLabel.Text = String.Format("I've created by the drop-down menu, {0}", newTabPage.Text);
        newLabel.Font = new Font("Tahoma", 9.75f, FontStyle.Bold);
        newLabel.Location = new Point(10, 10);
        newTabPage.Controls.Add(newLabel);
    };

    e.ContextMenu.Items.Insert(0, new ToolStripSeparator());
    e.ContextMenu.Items.Insert(0, menuItem);
    e.ContextMenu.Items.Add(new ToolStripSeparator());
    
    menuItem = new ToolStripMenuItem("My Menu Item");
    if (krbTabControl1.SelectedTab != null)
    {
        menuItem.Click += (thrower, ea) =>
        {
            MessageBox.Show(String.Format("Selected Tab Page: {0}", krbTabControl1.SelectedTab));
        };
    }
    e.ContextMenu.Items.Add(menuItem);
}

#endregion

 

”项,如下所示:

自定义下拉菜单
下拉菜单 预览
自定义菜单

防止标签页选择或标签页关闭用户的行动

行动 代码转储
TabPage选择
private void krbTabControl1_SelectedIndexChanging(object sender, SelectedIndexChangingEventArgs e)
{
    if (e.TabPage.Text == "IsSelectable?")
        e.Cancel = true;
}
TabPage关闭
private void krbTabControl1_TabPageClosing(object sender, SelectedIndexChangingEventArgs e)
{
    if (e.TabPage.Text == "Schedules")
    {
        if (MessageBox.Show("Do you want to remove the Schedules tab page?", 
            Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) 
            != DialogResult.Yes)
        {
            e.Cancel = true;
        }
    }
}

引用

欲知详情,请看以下书籍:

  • Pro .NET 2.0 Windows Forms and Custom Controls in C#, by Matthew MacDonald
  • Pro .NET 2.0 Graphics Programming, by Eric White

历史 

  • August 01, 2011 - Updated
    • Fixed drag and drop operation.
    • Fixed texture drawing for bottom alignment.
    • Added dynamic properties support.
    • Added mnemonic support.
    • Added show/hide capability to the tab pages by the drop down menu.
    • Added transparency support to the control caption bar and tab pages background.
    • Added keyboard user interaction.
    • Added serialize and deserialize support for data loading and saving(Xml and Binary serialization, you can choose one from the DataSaverAttribute class).
  • July 11, 2009 - First release
 

许可 

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

相关文章: