You need most of the code.
The actual TabControl and Custom TabPage class are not too extensive. In
order to modify the DesignerVerbs (Add Tab, Remove Tab) you must supply a
custom TabControlDesigner, and in VS2005 you must supply a custom
TabPageDesigner.
The TabPageDesigner is very simple as it only needs to be assigned as a
ScrollableControlDesigner, but the TabControlDesigner is quite complex as
the control needs to be navigated at DesignTime as well as at Runtime and
the System.Windows.Forms.Design.TabControlDesigner cannot be Inherited.
I've created an example in it's most basic form, but there's still a fair
amount of code here.
The System.Windows.Forms.TabPage will misbehave in the VS2005 IDE, and so I
have created a basic TabPage class with no special function. It is simply an
Inherited System.Windows.Forms.TabPage which uses a ScrollControlDesigner.
All of your Custom TabPages should be inherited from this class. For the
purpose of the example, I have created a RandomColorTabPage, just to show
implementation.
The Add verb/SmartTag will add a basic TabPage.
The CollectionEditor will add a basic TabPage if you simply click on the Add
button, but the button has a dropdown which will allow you to choose a
RandomColorTabPage to add instead.
To change the TabPage types that will show in the dropdown list, simply
modify the MyTabPageCollectionEditor's CreateNewItemTypes() method to return
the Type Array that you want.
To Change the TabPage type added via the Add Tab verb, simply modify the
type in the TabControlDesigner's OnAddPage() method.
At runtime you may add instances of System.Windows.Forms.TabPage without
penalty.
Here's the code: (note that you will need to add a reference to
System.Design.dll)
\\\
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
namespace Dotnetrix.Examples
{
[Designer(typeof(MyTabControlDesigner))]
public class MyTabControl : System.Windows.Forms.TabControl
{
[Editor(typeof(MyTabPageCollectionEditor), typeof(UITypeEditor))]
public new TabPageCollection TabPages
{
get
{
return base.TabPages;
}
}
internal class MyTabPageCollectionEditor : CollectionEditor
{
protected override CollectionEditor.CollectionForm
CreateCollectionForm()
{
CollectionForm baseForm = base.CreateCollectionForm();
baseForm.Text = "MyTabPage Collection Editor";
return baseForm;
}
public MyTabPageCollectionEditor(System.Type type)
: base(type)
{
}
protected override Type CreateCollectionItemType()
{
return typeof(RandomColorTabPage);
}
protected override Type[] CreateNewItemTypes()
{
return new Type[] { typeof(TabPage),
typeof(RandomColorTabPage) };
}
}
}
[Designer(typeof(System.Windows.Forms.Design.Scroll ableControlDesigner))]
public class TabPage : System.Windows.Forms.TabPage
{
public TabPage()
: base()
{
}
}
public class RandomColorTabPage : TabPage
{
public RandomColorTabPage()
: base()
{
this.BackColor = RandomColor();
}
private static Random ColorRandomizer = new Random();
private System.Drawing.Color RandomColor()
{
return System.Drawing.Color.FromArgb(ColorRandomizer.Next (256),
ColorRandomizer.Next(256),
ColorRandomizer.Next(256));
}
}
internal class MyTabControlDesigner :
System.Windows.Forms.Design.ParentControlDesigner
{
#region Private Instance Variables
private DesignerVerbCollection m_verbs = new
DesignerVerbCollection();
private IDesignerHost m_DesignerHost;
private ISelectionService m_SelectionService;
#endregion
public MyTabControlDesigner()
: base()
{
DesignerVerb verb1 = new DesignerVerb("Add Tab", new
EventHandler(OnAddPage));
DesignerVerb verb2 = new DesignerVerb("Remove Tab", new
EventHandler(OnRemovePage));
m_verbs.AddRange(new DesignerVerb[] { verb1, verb2 });
}
#region Properties
public override DesignerVerbCollection Verbs
{
get
{
if (m_verbs.Count == 2)
{
MyTabControl MyControl = (MyTabControl)Control;
if (MyControl.TabCount 0)
{
m_verbs[1].Enabled = true;
}
else
{
m_verbs[1].Enabled = false;
}
}
return m_verbs;
}
}
public IDesignerHost DesignerHost
{
get
{
if (m_DesignerHost == null)
m_DesignerHost =
(IDesignerHost)(GetService(typeof(IDesignerHost))) ;
return m_DesignerHost;
}
}
public ISelectionService SelectionService
{
get
{
if (m_SelectionService == null)
m_SelectionService =
(ISelectionService)(this.GetService(typeof(ISelect ionService)));
return m_SelectionService;
}
}
#endregion
void OnAddPage(Object sender, EventArgs e)
{
MyTabControl ParentControl = (MyTabControl)Control;
System.Windows.Forms.Control.ControlCollection oldTabs =
ParentControl.Controls;
RaiseComponentChanging(TypeDescriptor.GetPropertie s(ParentControl)["TabPages"]);
System.Windows.Forms.TabPage P =
(System.Windows.Forms.TabPage)(DesignerHost.Create Component(typeof(TabPage)));
P.Text = P.Name;
ParentControl.TabPages.Add(P);
RaiseComponentChanged(TypeDescriptor.GetProperties (ParentControl)["TabPages"],
oldTabs, ParentControl.TabPages);
ParentControl.SelectedTab = P;
SetVerbs();
}
void OnRemovePage(Object sender, EventArgs e)
{
MyTabControl ParentControl = (MyTabControl)Control;
System.Windows.Forms.Control.ControlCollection oldTabs =
ParentControl.Controls;
if (ParentControl.SelectedIndex < 0) return;
RaiseComponentChanging(TypeDescriptor.GetPropertie s(ParentControl)["TabPages"]);
DesignerHost.DestroyComponent(ParentControl.TabPag es[ParentControl.SelectedIndex]);
RaiseComponentChanged(TypeDescriptor.GetProperties (ParentControl)["TabPages"],
oldTabs, ParentControl.TabPages);
SelectionService.SetSelectedComponents(new IComponent[] {
ParentControl }, SelectionTypes.Auto);
SetVerbs();
}
private void SetVerbs()
{
MyTabControl ParentControl = (MyTabControl)Control;
switch (ParentControl.TabPages.Count)
{
case 0:
Verbs[1].Enabled = false;
break;
default:
Verbs[1].Enabled = true;
break;
}
}
private const int WM_NCHITTEST = 0x84;
private const int HTTRANSPARENT = -1;
private const int HTCLIENT = 1;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NCHITTEST)
{
//select tabcontrol when Tabcontrol clicked outside of
TabItem.
if (m.Result.ToInt32() == HTTRANSPARENT)
m.Result = (IntPtr)HTCLIENT;
}
}
private enum TabControlHitTest
{
TCHT_NOWHERE = 1,
TCHT_ONITEMICON = 2,
TCHT_ONITEMLABEL = 4,
TCHT_ONITEM = TCHT_ONITEMICON | TCHT_ONITEMLABEL
}
private const int TCM_HITTEST = 0x130D;
private struct TCHITTESTINFO
{
public System.Drawing.Point pt;
public TabControlHitTest flags;
}
protected override bool GetHitTest(System.Drawing.Point point)
{
if (this.SelectionService.PrimarySelection == this.Control)
{
TCHITTESTINFO hti = new TCHITTESTINFO();
hti.pt = this.Control.PointToClient(point);
hti.flags = 0;
System.Windows.Forms.Message m = new
System.Windows.Forms.Message();
m.HWnd = this.Control.Handle;
m.Msg = TCM_HITTEST;
IntPtr lparam =
System.Runtime.InteropServices.Marshal.AllocHGloba l(System.Runtime.InteropServices.Marshal.SizeOf(ht i));
System.Runtime.InteropServices.Marshal.StructureTo Ptr(hti,
lparam, false);
m.LParam = lparam;
base.WndProc(ref m);
System.Runtime.InteropServices.Marshal.FreeHGlobal (lparam);
if (m.Result.ToInt32() != -1)
return hti.flags != TabControlHitTest.TCHT_NOWHERE;
}
return false;
}
protected override void
OnPaintAdornments(System.Windows.Forms.PaintEventA rgs pe)
{
//Don't want DrawGrid dots.
}
//Fix the AllSizable selectionrule on DockStyle.Fill
public override System.Windows.Forms.Design.SelectionRules
SelectionRules
{
get
{
if (Control.Dock == System.Windows.Forms.DockStyle.Fill)
return
System.Windows.Forms.Design.SelectionRules.Visible ;
return base.SelectionRules;
}
}
}
}
///
HTH
--
Mick Doherty
http://dotnetrix.co.uk/nothing.html
"Pete Kane" <pj**********@uku.co.ukwrote in message
news:ez**************@TK2MSFTNGP03.phx.gbl...
Mick Doherty wrote:
>Either add the ToolBoxItemAttribute to your custom TabPage Class so that
you can drag and drop it from the toolbox, or Inherit from TabControl and
give it a custom TabPageCollection.
You'll find an example of the latter on my TabControls tips page
http://www.dotnetrix.co.uk/tabcontrols.html
For VS2005 you'll need to add a ScrollableControlDesigner to the custom
TabPage or it will misbehave in the IDE.
Thanks Mick, It (your sample tabcontrol with custom tabpages) looks very
impressive but which parts do I need to have my custom pages added by
default (i.e. when adding a tabcontrol in the IDE) and when adding
subsequent pages in the designer ? thanks a lot