在.NET 247上看到有人用VB.NET写了一个类, 可以实现TabControl的某个TabPage被disable后, Tab的文字显示为灰色, 且不能用鼠标切换为当前的活动Tab(如果当前已经是活动Tab则没有办法).
把它转为C#代码, 同时修改了它对键盘上箭头键的处理逻辑.
using System;
using System.Diagnostics;
using System.Collections;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
namespace UI.Controls
{
///
/// Summary description for DisableTabControl.
/// use DisableTabControl, you can really disable individual TabPage by
/// setting Enabled property to false(you cannot switch to dimmed page by mouse
/// or key board unless the current selected page is dimmed). usage:
/// 1. add reference Control.dll or the Control project
/// 2. using DigitalLab.UI.Controls
/// 3. Design your form
/// 4. find the variable name of your TabControl(Declaration and
/// initizlization)
/// 4.1 private System.Windows.Forms.TabControl tabControl1; ==>
/// private DigitalLab.UI.DisableTabControl tabControl1;
/// 4.2 in InitializeComponent()
/// tabControl1 = new System.Windows.Forms.TabControl(); ==>
/// tabControl1 = new DigitalLab.UI.Controls.DisableTabControl() ==>
/// 5. Switch to form designer
/// 5.1 set the Porperty DrawMode to OwnerDrawFixed
/// 5.2 add an handler to the event DrawItem
/// add the following code to the event handler:
/// tabControl1.DisableTabControl_DrawItem(sender,e);
/// 6 Enable/Disable a tabpage by
/// EnableDisablePage(tabpage, true/false)
/// public class DisableTabControl : System.Windows.Forms.TabControl
{
public DisableTabControl()
{
}
protected override void WndProc(ref Message m)
{
try
{
const int WM_LBUTTONDOWN = 0x201;
if( m.Msg == WM_LBUTTONDOWN )
{
Point pt = new Point( (int)m.LParam );
for(int index = 0; index < base.TabPages.Count; index++)
{
if( GetTabRect(index).Contains(pt) )
{
if (TabPages[index].Enabled == true)
{
base.WndProc(ref m);
}
return;
}
}
}
base.WndProc (ref m);
}
catch(Exception ex)
{
Debug.Assert(false, ex.ToString() );
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
int currentIndex = this.SelectedIndex;
try
{
if( e.KeyCode == Keys.Left && !(e.Alt && !e.Control ) )
{
int rewind = 0;
int i = currentIndex-1;
if( i == -1) i = TabPages.Count -1;
for(; rewind < 2 && i >= 0; i--)
{
if( TabPages[i].Enabled )
{
this.SelectedIndex = i;
break;
}
if( i == 0 )
{
rewind++;
i = TabPages.Count;
}
}
e.Handled = true;
}
else if(e.KeyCode == Keys.Right && !(e.Alt && !e.Control) )
{
int rewind = 0;
int i = currentIndex + 1;
if( i == TabPages.Count) i = 0;
for(; rewind < 2 && i < TabPages.Count; i++)
{
if( TabPages[i].Enabled )
{
this.SelectedIndex = i;
break;
}
if( i == TabPages.Count - 1)
{
rewind ++;
i = -1;
}
}
e.Handled = true;
}
else if( (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down) &&
!(e.Alt && !e.Control) )
{
if(this.Multiline == false)
{
e.Handled = false;
base.OnKeyDown (e);
return;
}
int targetIdx = -1;
Rectangle curr_rect = GetTabRect(currentIndex);
for(int i = 0; i < TabPages.Count; i++)
{
if( i == currentIndex) continue;
if( curr_rect.Contains(GetTabRect(i).X, curr_rect.Y) )
{
targetIdx = i;
break;
}
}
if( targetIdx != -1 && TabPages[targetIdx].Enabled == true)
{
this.SelectedIndex = targetIdx;
}
e.Handled = true;
}
base.OnKeyDown (e);
}
catch(Exception ex)
{
Debug.Assert(false, ex.ToString() );
}
}
///
/// you can also use tabPage.Enabled = false; tabControl.Refresh() directly
/// this method just give you a way to ignore Refresh();
/// ///
public void EnableDisablePage(TabPage pTabPage, bool enable )
{
bool curr_enable = pTabPage.Enabled ;
pTabPage.Enabled = enable;
if( curr_enable != enable)
this.Refresh();
}
public void DisableTabControl_DrawItem(object sender , System.Windows.Forms.DrawItemEventArgs e)
{
try
{
int intOffsetLeft ;
int intOffsetTop ;
RectangleF r = RectangleF.op_Implicit(e.Bounds);
RectangleF r2;
SolidBrush ItemBrush = new SolidBrush(this.BackColor);
Brush b = null;
if( this.TabPages[e.Index].Enabled )
b = Brushes.Black;
else
b = Brushes.Gray;
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
Bitmap im = null;
if(this.TabPages[e.Index].ImageIndex != -1 )
{
im = this.ImageList.Images[this.TabPages[e.Index].ImageIndex] as Bitmap;
}
if(this.TabPages[e.Index].ImageIndex != -1 )
r2 = new RectangleF(r.X + (im.Width / 2), r.Y, r.Width, r.Height);
else
r2 = new RectangleF(r.X, r.Y, r.Width, r.Height);
if( (int)(e.State & DrawItemState.Selected) != 0 )
{
e.Graphics.FillRectangle(ItemBrush, e.Bounds);
e.Graphics.DrawString(this.TabPages[e.Index].Text, e.Font, b, r2, sf);
//e.Graphics.DrawString(this.TabPages[e.Index].Text, e.Font, Brushes.Red, r2, sf);
intOffsetLeft = 5;
intOffsetTop = 5 ;
}
else
{
e.Graphics.DrawString(this.TabPages[e.Index].Text, e.Font, b, r2, sf);
//e.Graphics.DrawString(this.TabPages[e.Index].Text, e.Font, Brushes.Blue, r2, sf);
intOffsetLeft = 2;
intOffsetTop = 2 ;
}
if(this.TabPages[e.Index].ImageIndex != -1 )
{
this.ImageList.Draw(e.Graphics, Convert.ToInt32(r.Left) +
intOffsetLeft, Convert.ToInt32(r.Top) + intOffsetTop,
this.TabPages[e.Index].ImageIndex);
}
}
catch(Exception ex)
{
Debug.Assert(false, ex.ToString() );
}
}
}
}