Class Table

The KRBTabControl class provides a basic
implementation of its base control class but we need to create specific
classes, properties, methods and a few events for our control. To do
this, I have implemented custom classes.

Here you can review the class descriptions.

Class Name

Description

GradientTab

We fill the selected tab item rectangle and its borders with a specific gradient by using
this class member. It includes several kinds of properties for drawing
operations.

GradientTabConverter

Normally, there's no way to set the subproperties of the GradientTab class
at design time. To solve this problem, we need to create a custom type
converter which is a specialized class that derives from the ExpandableObjectConverter.

GradientTabEditor

To support a thumbnail view, we need to create a custom type editor.
Type editors give you the change to get a little fancy by creating a
custom thumbnail of the gradient in the properties window.

Hatcher

With this class, we fill the tab pages header area with various patterns. It contains four properties for painting operations.

HatcherConverter

A custom type converter for a live Hatcher object that derives from the ExpandableObjectConverter.

HatcherEditor

We define a thumbnail view for our BackgroundHatcher property in the properties window.

HatchStyleConverter

Bug! enumeration of HatchStyle, multiple values at the result while calling the HatchStyle enumeration. Therefore we provide the list of HatchStyle standard values.

CaptionGradient

You can determine a new caption gradient style for your tab control by using these class members.

CaptionGradientConverter

A custom type converter class for CaptionGradient members.

CaptionGradientEditor

A custom type editor class. For creating a custom thumbnail of the gradient in the properties window.

ButtonsCaption

You can change your active or inactive caption buttons's color by using these class members.

ButtonsCaptionConverter

A custom type converter class for ButtonsCaption members.

ButtonsCaptionEditor

A custom type editor class. For creating a custom thumbnail of the gradient in the properties window.

RandomizerCaption

RGBA (Red, Green, Blue and Alpha) colorizer for our control caption.
You can easily change your caption appearance by using this class
members.

RandomizerCaptionConverter

A simple ExpandableObjectConverter for CaptionRandomizer property.

CaptionColorChooserEditor

To add a modal dialog box capability to the CaptionRandomizer property, we need to create a new UITypeEditor.

TabpageExCollectionEditor

We need to create a custom collection editor for creating a new instance of TabPageEx class or destroying existing TabPageEx in our TabPages collection editor.

TabPageExPool

This collection class holds our hidden tab pages. You cannot hide a tab page at design-time. It only works in runtime mode.

Custom3DBorder

Our separator drawer class. It draws a vertical line connecting the two points specified by the coordinate pairs.

ArrowWindow

It appears only while we're dragging a tab item on the another tab item.

UpDown32

To hide or destroy system "msctls-updown32" scroller button from the container, we need to create a native window class that derives from the NativeWindow.

Scroller

The scroller class includes left and right RolloverUpDown control. You can change scroller style from the properties dialog.

RolloverUpDown

With the rollover updown control, very little work is performed with GDI+. Instead, updown images for all the four states are prepared in a separate program, and imported into the application as resources. These images are then assigned to the control which switches between them seamlessly (by deriving a class from UpDownBase).

UpDownBase

To make a custom updown button scroller, it makes most sense to derive directly from the Control class, because you need to implement all the drawing operations on your own. The UpDownBase control is declared as an abstract class so it cannot be instantiated directly.

KRBTabControlDesigner

To add design-time conveniences, like designer verbs or smart tags
and also remove inappropriate events or properties from view (or add
design-time-only events, properties and to create dynamic properties for
our custom control). To create a basic control designer, begin by
deriving a class from ParentControlDesigner.

KRBTabControlActionList

This class has two roles-it configures the collection of DesignerActionItem instances
for the smart tag and when a command or change is made, it performs
the corresponding operation on the linked control.

TabPageEx

Our custom tab page class. We need to change and add some properties on it.

CaptionColorChooser

To change RGBA values on the caption bitmap. We need to use a modal dialog box for changing color attributes.

ContextMenuShownEventArgs

This class holds our drop-down menu item parameters.

SelectedIndexChangingEventArgs

To prevent tab page selection or close, we need to create a custom EventArgs class.

Control Border Styles

KRBTabControl Border Styles

Border Style

Preview

Solid

Dotted

Dashed

Control Properties Table

A few properties from our KRBTabControl.

Property

Description

TabStyles

Gets or Sets the selected tab page style.

BorderColor

Gets or Sets the border color of the control.

TabPageCloseIconColor

Gets or Sets the icon color of the selected tab item.

TabHOffset

Gets or Sets the distance in pixels, between the left edge of the first tab page and the left edge of its container's client area, the value must be in the range of -2 to 5 pixel size.

HeaderStyle

Gets or Sets the background style of the tab page header.

TabGradient

Gets or Sets the gradient colors of the selected tab page item.

GradientCaption

You can determine a new caption gradient style and colors for your tab control.

Determines whether the active tab is stretched to its parent container or not.

IsDrawHeader

Determines whether the tab header background is draw or not.

IsCaptionVisible

Determines whether the tab control caption is visible or not.

IsDrawEdgeBorder

Determines whether the tab control's edge border is draw or not, you must set the IsCaptionVisible's value to false for this change to take effect.

IsUserInteraction

Provides keyboard support to the user for tab control operations.

IsDrawTabSeparator

Determines whether the tab separator line is visible or not between the tab pages.

IsDocumentTabStyle

Determines whether the tab control like as document tab style or not.

Tab Page Styles

KRBTabControl Tab Page Styles

Tab Page Style

Preview

KRBStyle

OfficeXP

VS2010

Control Events

I have implemented a few events for control design and end-user notification.

KRBTabControl Events

Event Name

Description

DrawHeaderChanged

Event raised when the value of the IsDrawHeader property is changed.

CaptionVisibleChanged

Event raised when the value of the IsCaptionVisible property is changed.

StretchToParentChanged

Event raised when the value of the HeaderVisibility(StretchToParent) property is changed.

TabPageClosing

Occurs when a tab page is being closed.

SelectedIndexChanging

Occurs when a tab page is being selected.

ContextMenuShown

Occurs when a user clicks the drop-down icon on the caption if it's visible.

Transparent Background Support

Preview

CaptionBar

TabPages

Empty Container

If your tab pages count is less than one, you'll see a empty tab container like the following.

Transparent background support for tabpages and caption bar.

The ExpandableObjectConverter

Unfortunately, there’s no way to set a custom object subproperties at
design time.To solve this problem, you need to create a custom type
converter, which is a specialized class that can convert a custom object
to a string, and then convert the string back to a live custom object. If you don't use a type converter and look in the Properties window, you’ll see a piece of static text that shows the result of calling ToString() on the custom object.

A number of object properties are supported by Windows Forms controls. The best example is Font, which refers to a full-fledged Font object with properties like Bold, Italic, Name, and so on. When you set the Fontproperty in the Properties window, you don’t need to type all this information in a single, correctly formatted string. Instead, you can expand the Font property by clicking the plus (+) box and editing all of the Font subproperties individually.

You can enable the same type of editing with your own custom object types. You actually have two choices—you can use the ExpandableObjectConverter directly, or you can create a custom type converter that derives from the ExpandableObjectConverter. If you use this approach, you’ll have the benefit of the string representation and the ability to expand the property to see subproperties.

The first step is to create a custom class that derives from the base class System.ComponentModel.ExpandableObjectConverter, as shown here:

Attaching a Type Converter

There are two ways to attach a type converter. The approach you
should use in most cases is to link the custom type to the type
converter by adding the TypeConverter attribute to the class declaration.

Use this to return true if you are providing a PaintValue()implementation.

PaintValue()

Invoked to paint a graphical thumbnail that represents the value in the Properties window.

A Modal Type Editor

A modal type editor shows an ellipsis (...) button next to the property value. When this button
is clicked, a dialog box appears that allows the developer to change the property value.

CaptionColorChooser

The CaptionColorChooser is a modal form. It makes sense to keep it out of the code editor. You can accomplish this by adding the internal keyword to the class declaration.

internalpartialclass CaptionColorChooser : Form
{
// To do something.
}

The real trick in this example is that the modal form you create
for editing the property needs a way to receive information from the
custom control object. To do this, you should create a few public instance to your editing control that accepts all the information it needs.

Here’s the details for storing the instance-supplied information:

#region Instance Members
public KRBTabControl contextInstance;
public ICaptionRandomizer Randomizer;
#endregion

Each NumericUpDown value can be changed by the user in the modal dialog box. So we need to create an event handler for each NumericUpDown control and then we should be updated current view on the form.

After than, we need to connect this type editor to the RandomizerCaption class using the Editor
attribute. The following code snippet shows that how you can add this
attribute to your appropriate class declaration. As mentioned above, you
can also attach this type editor to the appropriate property using the same attribute.

All you need to do now is fill in the type editor code. First, we choose the modal style for our UITypeEditor. After than, We turn down thumbnails. Because; our worker class(RandomizerCaption) does not implement the drawing behaviour for design-time. And finally, in the EditValue() method you create an instance of the CaptionColorChooser form, and set its initial properties in the using scope, as shown here:

Painting a Thumbnail

Type editors also give you the chance to get a little fancy by
creating a custom thumbnail of the gradient in the Properties window. To
add this extra bit of finesse, all you need to do is create a type
editor and override the PaintValue() method. Here’s the complete example from the GradientTabEditor class:

Shortcut Keys

If IsUserInteraction property is enabled, provides keyboard support to the user for tab control operations.

Keyboard Keys

Keys

Description

End

Selects last tab page in the container.

Home

Selects first tab page in the container.

Left

Selects the tab on the left side of the currently selected tab page in the container.

Right

Selects the tab on the right side of the currently selected tab page in the container.

Insert

When a user is pressed to "Insert" key, a question dialog box appears that allows the developer to insert a new tab page. As shown in the below picture;

Delete

Removes the selected tab page from the container. When this key is pressed, a dialog box appears that allows the developer to remove currently selected tab page from the container as shown here.

The KRBTabControlDesigner

Control designers allow you to manage the design-time behavior and
the design-time interface (properties and events) exposed by your
control. Although control designers are quite complex pieces of the
Windows Forms infrastructure, it’s not difficult to customize an
existing control designer to add new features.

You can derive a custom control designer to use with your custom controls. Why would you create your own designer?

To tailor the design-time appearance of the control so that it differs from the runtime appearance (for example, adding a border around an empty panel).

To add support for controls that contain other controls (like the toolbar) or controls with special design-time needs (like menus).

At design time, the designer infrastructure attaches a designer to
each component as it is sited on a form. (If more than one instance of
the same component is added to a form, Visual Studio
will reuse the same designer for all instances.) Once this connection is
established, the control designer has the ability to take part in the
interaction between the developer and the control.

To create a custom designer for your container like control, begin by deriving a class from ParentControlDesigner. The following code snippet shows how you can create a control designer for your controls.

You can then add functionality to your control designer by overriding
the built-in methods. When you’re finished, you need to link the custom
control designer to the appropriate control. To do this, you apply the Designer attribute to the control declaration and specify the appropriate designer type. Here’s an example that links the KRBTabControlDesigner to the KRBTabControl control:

Designers provide six methods from the IDesignerFilter interface that you can override to filter properties, events, and attributes. These methods are listed in the below table.

IDesignerFilter Methods

Method

Description

PostFilterAttributes

Override this method to remove unused or inappropriate attributes.

PostFilterEvents

Override this method to remove unused or inappropriate events.

PostFilterProperties

Override this method to remove unused or inappropriate properties.

PreFilterAttributes

Override this method to add attributes.

PreFilterEvents

Override this method to add events.

PreFilterProperties

Override this method to add properties.

Technically, the filtering methods allow you to modify a System.ComponentModel.TypeDescriptorobject
that stores the property, attribute, and event information for your
custom control. Visual Studio uses the information from this TypeDescriptor to determine what it makes available in the design-time environment.

Here’s an example that removes the inappropriate properties specified in the following code dump.

Important Note: As a general rule, always call the base method first in the PreFilterXxx() methods and last in the PostFilterXxx() methods. This way, all designer classes are given the proper opportunity to apply their changes. The ControlDesigner and ComponentDesigner use these methods to add properties like Visible, Enabled, Name, and Locked.

Dynamic Properties

To create dynamic properties for our custom controls. We need to override the PreFilterProperties method. In addition that, we need to change the properties attributes by using the TypeDescriptor.CreateProperty() in the same method. The following code snippet shows how you can apply this behaviour to your custom controls.

You still need to link each custom attribute to the appropriate property using the System.ComponentModel.RefreshProperties
attribute in your custom control class. The following code snippet
shows how you can add this attribute to your appropriate property
declaration and specify the appropriate identifier type.

For example, when the KRBTabControl.HeaderStyle property is changed by the user. We show or hide the BackgroundColor, BackgroundImageand BackgroundHatcherproperties to the end-user.

Smart Tags

The latest versions of Visual Studio include a new feature for
creating a rich design-time experience—smart tags. Smart tags are the
pop-up windows that appear next to a control when you click the tiny
arrow in the corner.

Smart tags are similar to menus in that they have a list of items. However, these items can be commands (which are rendered like hyperlinks), or other controls like check boxes, drop-down lists, and more. They can also include static descriptive text. In this way, a smart tag can act like a mini Properties window.

The following picture shows an example of the custom smart tag. It allows the developer to set a combination of KRBTabControl properties.

A sample Smart Tag window

To create this smart tag, you need the following ingredients:

A collection of DesignerActionItem objects: Each DesignerActionItem represents a single item in the smart tag.

An action list class: This class has two roles—it configures the collection of DesignerActionItem instances
for the smart tag and, when a command or change is made, it performs
the corresponding operation on the linked control.

A control designer: This hooks your action list up to the control so the smart tag appears at design time.

The Action List

Creating a smart tag is conceptually similar to adding designer verbs—you
override a method in your control designer, and return a collection of
commands you want to support. (This list of commands is called an action list.)

However, smart tags allow many more options than designer verbs, and
so the associated code is likely to be more complex. To keep it all
under control, it’s a good idea to separate your code by creating a
custom class that encapsulates your action list. This custom class
should derive from DesignerActionList (in the System.ComponentModel.Designnamespace).

Here’s an example that creates an action list that’s intended for use with the KRBTabControl:

You should add a single constructor to the action list that requires
the matching control type. You can then store the reference to the
control in a member variable. This isn’t required, because the base ActionList class does provide a Component
property that provides access to your control. However, by using this
approach, you gain the convenience of strongly typed access to your
control.

To create your smart tag, you need to build a DesignerActionItemCollection that combines your group of DesignerActionItem objects. Order is important in this collection, because Visual Studio will add the DesignerActionItem objects to the smart tag from top to bottom in the order they appear.

To build your action list, you override the DesignerActionList.GetSortedActionItems() method, create the DesignerActionItemCollection, add each DesignerActionItem to it, and then return the collection. Depending on the complexity of your smart tag, this may take several steps.

The first step is to create the headers that divide the smart tag
into separate regions. You can then add other items into these
categories, as shown here:

You still need to connect it to your control. To add this action-list to your control, you need to override the ActionLists property in your custom designer, create a new DesignerActionListCollection, and add the appropriate DesignerActionList
object entries. Your control designer handles the action item event,
generally by updating the associated control. Notice that the action
list isn’t created each time ActionList is called instead, it’s cached it as private member variable to optimize performance.

Drag and Drop Support

If AllowDrop property is enable, you can drag currently selected tab page over the other tab pages. And also you can drag your tab pages from one tab container to another.

Tab Header Styles

KRBTabControl Header Styles

Header Style

Preview

Solid

Hatch

Texture

Drop Down Menu Customizing

There are two ways to customize your drop-down menu. The approach you should use in most cases is to handle the ContextMenuShown event. It passes an instance of ContextMenuShownEventArgs to the method for menu customizing.

And another option is, when creating an inherited control with a different visual appearance, you must provide code to customize drop-down menu by overriding the OnContextMenuShown method. You can also hide or show your tab pages in the same menu. You'll see the available tab pages under the "Available Tab Pages" item, as shown here:

in the example, if you try to close SCHEDULES tabpage, it will bring up a dialogbox to confirm your choice, if you choose NO, the MOUSE pointer will be reset to the position where the close button is, that is annoying. the reason resetting the MOUSE pointer is that the state of the close button remaining HOVER even if the MOUSE has been moved out of it. this can be fixed as following:

1) in OnMouseClick and OnMouseDoubleClick event, check if the Cursor.Position is outside the close button region, if it does, set the state of the close button to ButtonState.Normal and invalidate the close button retangle to repaint it. so modify the code

Yes this is a problem for this control(OwnerDraw controls, width value is the same for all the tabs), If you want to look at my other tab control, you can try it. http://www.codeproject.com/Articles/456580/NeoTabControl-Library

Because, you are attempting to add a disposed page control to control's container. You cannot add a disposed tabpage control to container. When you're removing a tabpage from the tab control, this page control and its sub controls also to be disposed.

You can see your text of the tabpage but you cannot access it from your control. Because it is disposed.

"So long as … social condemnation, which, in the face of civilization, artificially creates hells on earth, and complicates divine destiny, with human fatality … so long as three problems of the age: degradation of man by poverty; ruin of women by starvation; dwarfing of childhood by physical and spiritual night: are not solved: so long as social asphyxia shall be possible … so long as ignorance and misery remain on earth, books like this cannot be useless." Victor Hugo, "Les Misérables," 1862

Hi, when I dragged KRBTabControl.dll into my toolbox, inserted in my form and finally Debugged I get InvalidCastException Error: System.Windows.Forms.TabPage in type KRBTabControl.TabPageEx... why?
thanks