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 TabControlDesig ner, and in VS2005 you must supply a custom
TabPageDesigner .
The TabPageDesigner is very simple as it only needs to be assigned as a
ScrollableContr olDesigner, but the TabControlDesig ner is quite complex as
the control needs to be navigated at DesignTime as well as at Runtime and
the System.Windows. Forms.Design.Ta bControlDesigne r 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 ScrollControlDe signer.
All of your Custom TabPages should be inherited from this class. For the
purpose of the example, I have created a RandomColorTabP age, just to show
implementation.
The Add verb/SmartTag will add a basic TabPage.
The CollectionEdito r 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
RandomColorTabP age to add instead.
To change the TabPage types that will show in the dropdown list, simply
modify the MyTabPageCollec tionEditor's CreateNewItemTy pes() 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 TabControlDesig ner'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.d ll)
\\\
using System;
using System.Componen tModel;
using System.Componen tModel.Design;
using System.Drawing. Design;
namespace Dotnetrix.Examp les
{
[Designer(typeof (MyTabControlDe signer))]
public class MyTabControl : System.Windows. Forms.TabContro l
{
[Editor(typeof(M yTabPageCollect ionEditor), typeof(UITypeEd itor))]
public new TabPageCollecti on TabPages
{
get
{
return base.TabPages;
}
}
internal class MyTabPageCollec tionEditor : CollectionEdito r
{
protected override CollectionEdito r.CollectionFor m
CreateCollectio nForm()
{
CollectionForm baseForm = base.CreateColl ectionForm();
baseForm.Text = "MyTabPage Collection Editor";
return baseForm;
}
public MyTabPageCollec tionEditor(Syst em.Type type)
: base(type)
{
}
protected override Type CreateCollectio nItemType()
{
return typeof(RandomCo lorTabPage);
}
protected override Type[] CreateNewItemTy pes()
{
return new Type[] { typeof(TabPage) ,
typeof(RandomCo lorTabPage) };
}
}
}
[Designer(typeof (System.Windows .Forms.Design.S crollableContro lDesigner))]
public class TabPage : System.Windows. Forms.TabPage
{
public TabPage()
: base()
{
}
}
public class RandomColorTabP age : TabPage
{
public RandomColorTabP age()
: 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 MyTabControlDes igner :
System.Windows. Forms.Design.Pa rentControlDesi gner
{
#region Private Instance Variables
private DesignerVerbCol lection m_verbs = new
DesignerVerbCol lection();
private IDesignerHost m_DesignerHost;
private ISelectionServi ce m_SelectionServ ice;
#endregion
public MyTabControlDes igner()
: base()
{
DesignerVerb verb1 = new DesignerVerb("A dd Tab", new
EventHandler(On AddPage));
DesignerVerb verb2 = new DesignerVerb("R emove Tab", new
EventHandler(On RemovePage));
m_verbs.AddRang e(new DesignerVerb[] { verb1, verb2 });
}
#region Properties
public override DesignerVerbCol lection Verbs
{
get
{
if (m_verbs.Count == 2)
{
MyTabControl MyControl = (MyTabControl)C ontrol;
if (MyControl.TabC ount 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(typ eof(IDesignerHo st)));
return m_DesignerHost;
}
}
public ISelectionServi ce SelectionServic e
{
get
{
if (m_SelectionSer vice == null)
m_SelectionServ ice =
(ISelectionServ ice)(this.GetSe rvice(typeof(IS electionService )));
return m_SelectionServ ice;
}
}
#endregion
void OnAddPage(Objec t sender, EventArgs e)
{
MyTabControl ParentControl = (MyTabControl)C ontrol;
System.Windows. Forms.Control.C ontrolCollectio n oldTabs =
ParentControl.C ontrols;
RaiseComponentC hanging(TypeDes criptor.GetProp erties(ParentCo ntrol)["TabPages"]);
System.Windows. Forms.TabPage P =
(System.Windows .Forms.TabPage) (DesignerHost.C reateComponent( typeof(TabPage) ));
P.Text = P.Name;
ParentControl.T abPages.Add(P);
RaiseComponentC hanged(TypeDesc riptor.GetPrope rties(ParentCon trol)["TabPages"],
oldTabs, ParentControl.T abPages);
ParentControl.S electedTab = P;
SetVerbs();
}
void OnRemovePage(Ob ject sender, EventArgs e)
{
MyTabControl ParentControl = (MyTabControl)C ontrol;
System.Windows. Forms.Control.C ontrolCollectio n oldTabs =
ParentControl.C ontrols;
if (ParentControl. SelectedIndex < 0) return;
RaiseComponentC hanging(TypeDes criptor.GetProp erties(ParentCo ntrol)["TabPages"]);
DesignerHost.De stroyComponent( ParentControl.T abPages[ParentControl.S electedIndex]);
RaiseComponentC hanged(TypeDesc riptor.GetPrope rties(ParentCon trol)["TabPages"],
oldTabs, ParentControl.T abPages);
SelectionServic e.SetSelectedCo mponents(new IComponent[] {
ParentControl }, SelectionTypes. Auto);
SetVerbs();
}
private void SetVerbs()
{
MyTabControl ParentControl = (MyTabControl)C ontrol;
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(re f m);
if (m.Msg == WM_NCHITTEST)
{
//select tabcontrol when Tabcontrol clicked outside of
TabItem.
if (m.Result.ToInt 32() == HTTRANSPARENT)
m.Result = (IntPtr)HTCLIEN T;
}
}
private enum TabControlHitTe st
{
TCHT_NOWHERE = 1,
TCHT_ONITEMICON = 2,
TCHT_ONITEMLABE L = 4,
TCHT_ONITEM = TCHT_ONITEMICON | TCHT_ONITEMLABE L
}
private const int TCM_HITTEST = 0x130D;
private struct TCHITTESTINFO
{
public System.Drawing. Point pt;
public TabControlHitTe st flags;
}
protected override bool GetHitTest(Syst em.Drawing.Poin t point)
{
if (this.Selection Service.Primary Selection == this.Control)
{
TCHITTESTINFO hti = new TCHITTESTINFO() ;
hti.pt = this.Control.Po intToClient(poi nt);
hti.flags = 0;
System.Windows. Forms.Message m = new
System.Windows. Forms.Message() ;
m.HWnd = this.Control.Ha ndle;
m.Msg = TCM_HITTEST;
IntPtr lparam =
System.Runtime. InteropServices .Marshal.AllocH Global(System.R untime.InteropS ervices.Marshal .SizeOf(hti));
System.Runtime. InteropServices .Marshal.Struct ureToPtr(hti,
lparam, false);
m.LParam = lparam;
base.WndProc(re f m);
System.Runtime. InteropServices .Marshal.FreeHG lobal(lparam);
if (m.Result.ToInt 32() != -1)
return hti.flags != TabControlHitTe st.TCHT_NOWHERE ;
}
return false;
}
protected override void
OnPaintAdornmen ts(System.Windo ws.Forms.PaintE ventArgs pe)
{
//Don't want DrawGrid dots.
}
//Fix the AllSizable selectionrule on DockStyle.Fill
public override System.Windows. Forms.Design.Se lectionRules
SelectionRules
{
get
{
if (Control.Dock == System.Windows. Forms.DockStyle .Fill)
return
System.Windows. Forms.Design.Se lectionRules.Vi sible;
return base.SelectionR ules;
}
}
}
}
///
HTH
--
Mick Doherty
http://dotnetrix.co.uk/nothing.html
"Pete Kane" <pj**********@u ku.co.ukwrote in message
news:ez******** ******@TK2MSFTN GP03.phx.gbl...
Mick Doherty wrote:
>Either add the ToolBoxItemAttr ibute 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 TabPageCollecti on.
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 ScrollableContr olDesigner 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