SunnyUI/SunnyUI/Controls/UITabControl.cs

1204 lines
39 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
* SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
* CopyRight (C) 2012-2023 ShenYongHua(沈永华).
* QQ群56829229 QQ17612584 EMailSunnyUI@QQ.Com
*
* Blog: https://www.cnblogs.com/yhuse
* Gitee: https://gitee.com/yhuse/SunnyUI
* GitHub: https://github.com/yhuse/SunnyUI
*
* SunnyUI.dll can be used for free under the GPL-3.0 license.
* If you use this code, please keep this note.
* 如果您使用此代码,请保留此说明。
******************************************************************************
* 文件名称: UITabControl.cs
* 文件说明: 标签控件
* 当前版本: V3.1
* 创建日期: 2020-01-01
*
* 2020-01-01: V2.2.0 增加文件说明
* 2020-06-27: V2.2.5 重绘左右选择按钮
* 2020-08-12: V2.2.7 标题垂直居中
* 2021-04-01: V3.0.2 修改第一个TabPage关不掉的Bug
* 2021-06-08: V3.0.4 Tab页标题选中高亮颜色增加可调整高度
* 2021-07-14: V3.0.5 支持Tab在下方显示
* 2021-08-14: V3.0.6 增加DisposeTabPageAfterRemove标志移除TabPage后是否自动销毁TabPage
* 2022-01-02: V3.0.9 增加角标
* 2022-01-13: V3.1.0 修改删除页面时的页面跳转
* 2022-04-18: V3.1.5 关闭按钮增加鼠标移入的效果
* 2022-04-20: V3.1.5 不显示标签页时屏蔽左右键
* 2022-05-11: V3.1.8 修复屏蔽左右键后其他控件无法使用左右键的问题
* 2022-05-17: V3.1.9 修复了一个首页无法关闭的问题
* 2022-06-19: V3.2.0 多页面框架关闭页面时执行UIPage的FormClosed事件
* 2023-05-12: V3.3.6 重构DrawString函数
******************************************************************************/
using Sunny.UI.Win32;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Sunny.UI
{
public sealed class UITabControl : TabControl, IStyleInterface, IZoomScale
{
private readonly UITabControlHelper Helper;
private int DrawedIndex = -1;
private readonly Timer timer;
public UITabControl()
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
DoubleBuffered = true;
UpdateStyles();
ItemSize = new Size(150, 40);
DrawMode = TabDrawMode.OwnerDrawFixed;
base.Font = UIStyles.Font();
AfterSetFillColor(FillColor);
Version = UIGlobal.Version;
Helper = new UITabControlHelper(this);
timer = new Timer();
timer.Interval = 500;
timer.Tick += Timer_Tick;
DisposeTabPageAfterRemove = true;
AutoClosePage = true;
tabSelectedForeColor = UIStyles.Blue.TabControlTabSelectedColor;
tabSelectedHighColor = UIStyles.Blue.TabControlTabSelectedColor;
_fillColor = UIStyles.Blue.TabControlBackColor;
}
[Browsable(false), DefaultValue(null)]
public IFrame Frame
{
get; set;
}
/// <summary>
/// 禁止控件跟随窗体缩放
/// </summary>
[DefaultValue(false), Category("SunnyUI"), Description("禁止控件跟随窗体缩放")]
public bool ZoomScaleDisabled { get; set; }
/// <summary>
/// 控件缩放前在其容器里的位置
/// </summary>
[Browsable(false), DefaultValue(typeof(Rectangle), "0, 0, 0, 0")]
public Rectangle ZoomScaleRect { get; set; }
/// <summary>
/// 设置控件缩放比例
/// </summary>
/// <param name="scale">缩放比例</param>
public void SetZoomScale(float scale)
{
}
private ConcurrentDictionary<TabPage, string> TipsTexts = new ConcurrentDictionary<TabPage, string>();
public void SetTipsText(TabPage tabPage, string tipsText)
{
if (TipsTexts.ContainsKey(tabPage))
TipsTexts[tabPage] = tipsText;
else
TipsTexts.TryAdd(tabPage, tipsText);
Invalidate();
}
private string GetTipsText(TabPage tabPage)
{
return TipsTexts.ContainsKey(tabPage) ? TipsTexts[tabPage] : string.Empty;
}
private Color tipsColor = Color.Red;
[Description("角标背景颜色"), Category("SunnyUI")]
[DefaultValue(typeof(Color), "Red")]
public Color TipsColor
{
get => tipsColor;
set
{
tipsColor = value;
Invalidate();
}
}
private Color tipsForeColor = Color.White;
[DefaultValue(typeof(Color), "White"), Category("SunnyUI"), Description("角标文字颜色")]
public Color TipsForeColor
{
get => tipsForeColor;
set
{
tipsForeColor = value;
Invalidate();
}
}
private Font tipsFont = UIStyles.SubFont();
[Description("角标文字字体"), Category("SunnyUI")]
[DefaultValue(typeof(Font), "宋体, 9pt")]
public Font TipsFont
{
get { return tipsFont; }
set
{
if (!tipsFont.Equals(value))
{
tipsFont = value;
Invalidate();
}
}
}
private float DefaultFontSize = -1;
public void SetDPIScale()
{
if (!UIDPIScale.NeedSetDPIFont()) return;
if (DefaultFontSize < 0) DefaultFontSize = this.Font.Size;
this.SetDPIScaleFont(DefaultFontSize);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
timer?.Stop();
timer?.Dispose();
}
private string mainPage = "";
[DefaultValue(true)]
[Description("主页名称,此页面不显示关闭按钮"), Category("SunnyUI")]
public string MainPage
{
get => mainPage;
set
{
mainPage = value;
Invalidate();
}
}
private void Timer_Tick(object sender, EventArgs e)
{
timer.Stop();
DrawedIndex = SelectedIndex;
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (ForbidCtrlTab)
{
switch (keyData)
{
case (Keys.Tab | Keys.Control):
//组合键在调试时不容易捕获可以先按住Ctrl键此时在断点处已经捕获然后按下Tab键都释放后再进入断点处单步向下执行
//此时会分两次进入断点第一次好像是处理Ctrl键第二次处理组合键
return true;
}
}
if (Focused && !TabVisible)
{
switch (keyData)
{
case Keys.Left:
//if (TabVisible)
return true;
case Keys.Right:
//if (TabVisible)
return true;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
[DefaultValue(true)]
[Description("是否禁用Ctrl+Tab"), Category("SunnyUI")]
public bool ForbidCtrlTab { get; set; } = true;
public bool SelectPage(int pageIndex) => Helper.SelectPage(pageIndex);
public bool SelectPage(Guid pageGuid) => Helper.SelectPage(pageGuid);
public bool RemovePage(int pageIndex) => Helper.RemovePage(pageIndex);
public bool RemovePage(Guid guid) => Helper.RemovePage(guid);
public void RemoveAllPages(bool keepMainPage = true) => Helper.RemoveAllPages(keepMainPage);
public UIPage GetPage(int pageIndex) => Helper.GetPage(pageIndex);
public UIPage GetPage(Guid guid) => Helper.GetPage(guid);
public void SetTipsText(int pageIndex, string tipsText) => Helper.SetTipsText(pageIndex, tipsText);
public void SetTipsText(Guid guid, string tipsText) => Helper.SetTipsText(guid, tipsText);
public void AddPages(params UIPage[] pages)
{
foreach (var page in pages) AddPage(page);
}
public void AddPage(UIPage page)
{
Helper.AddPage(page);
PageAdded?.Invoke(this, new UIPageEventArgs(page));
}
internal event OnUIPageChanged PageAdded;
internal event OnUIPageChanged PageRemoved;
public void AddPage(int pageIndex, UITabControl page) => Helper.AddPage(pageIndex, page);
public void AddPage(int pageIndex, UITabControlMenu page) => Helper.AddPage(pageIndex, page);
public void AddPage(Guid guid, UITabControl page) => Helper.AddPage(guid, page);
public void AddPage(Guid guid, UITabControlMenu page) => Helper.AddPage(guid, page);
public T GetPage<T>() where T : UIPage => Helper.GetPage<T>();
public List<T> GetPages<T>() where T : UIPage => Helper.GetPages<T>();
public string Version
{
get;
}
private Color _fillColor = UIColor.LightBlue;
private Color tabBackColor = Color.FromArgb(56, 56, 56);
/// <summary>
/// Tag字符串
/// </summary>
[DefaultValue(null)]
[Description("获取或设置包含有关控件的数据的对象字符串"), Category("SunnyUI")]
public string TagString
{
get; set;
}
/// <summary>
/// 自定义主题风格
/// </summary>
[DefaultValue(false)]
[Description("获取或设置可以自定义主题风格"), Category("SunnyUI")]
public bool StyleCustomMode
{
get; set;
}
private HorizontalAlignment textAlignment = HorizontalAlignment.Center;
[DefaultValue(HorizontalAlignment.Center)]
[Description("文字显示方向"), Category("SunnyUI")]
public HorizontalAlignment TextAlignment
{
get => textAlignment;
set
{
textAlignment = value;
Invalidate();
}
}
private bool tabVisible = true;
[DefaultValue(true)]
[Description("标签页是否显示"), Category("SunnyUI")]
public bool TabVisible
{
get => tabVisible;
set
{
tabVisible = value;
if (!tabVisible)
{
ItemSize = new Size(0, 1);
}
else
{
if (ItemSize == new Size(0, 1))
{
ItemSize = new Size(150, 40);
}
}
Invalidate();
}
}
/// <summary>
/// 当使用边框时填充颜色,当值为背景色或透明色或空值则不填充
/// </summary>
[Description("当使用边框时填充颜色,当值为背景色或透明色或空值则不填充"), Category("SunnyUI")]
[DefaultValue(typeof(Color), "243, 249, 255")]
public Color FillColor
{
get => _fillColor;
set
{
_fillColor = value;
AfterSetFillColor(value);
SetStyleCustom();
}
}
private void SetStyleCustom(bool needRefresh = true)
{
_style = UIStyle.Custom;
if (needRefresh) Invalidate();
}
/// <summary>
/// 边框颜色
/// </summary>
[Description("边框颜色"), Category("SunnyUI")]
[DefaultValue(typeof(Color), "56, 56, 56")]
public Color TabBackColor
{
get => tabBackColor;
set
{
if (tabBackColor != value)
{
tabBackColor = value;
_menuStyle = UIMenuStyle.Custom;
Invalidate();
}
}
}
private Color tabSelectedColor = Color.FromArgb(36, 36, 36);
/// <summary>
/// 边框颜色
/// </summary>
[Description("选中Tab页背景色"), Category("SunnyUI")]
[DefaultValue(typeof(Color), "36, 36, 36")]
public Color TabSelectedColor
{
get => tabSelectedColor;
set
{
if (tabSelectedColor != value)
{
tabSelectedColor = value;
_menuStyle = UIMenuStyle.Custom;
Invalidate();
}
}
}
private Color tabSelectedForeColor = UIColor.Blue;
/// <summary>
/// 边框颜色
/// </summary>
[Description("选中Tab页字体色"), Category("SunnyUI")]
[DefaultValue(typeof(Color), "80, 160, 255")]
public Color TabSelectedForeColor
{
get => tabSelectedForeColor;
set
{
if (tabSelectedForeColor != value)
{
tabSelectedForeColor = value;
SetStyleCustom();
}
}
}
private Color tabUnSelectedForeColor = Color.FromArgb(240, 240, 240);
/// <summary>
/// 边框颜色
/// </summary>
[Description("未选中Tab页字体色"), Category("SunnyUI")]
[DefaultValue(typeof(Color), "240, 240, 240")]
public Color TabUnSelectedForeColor
{
get => tabUnSelectedForeColor;
set
{
if (tabUnSelectedForeColor != value)
{
tabUnSelectedForeColor = value;
_menuStyle = UIMenuStyle.Custom;
Invalidate();
}
}
}
private Color tabSelectedHighColor = UIColor.Blue;
/// <summary>
/// 边框颜色
/// </summary>
[Description("选中Tab页高亮"), Category("SunnyUI")]
[DefaultValue(typeof(Color), "80, 160, 255")]
public Color TabSelectedHighColor
{
get => tabSelectedHighColor;
set
{
if (tabSelectedHighColor != value)
{
tabSelectedHighColor = value;
SetStyleCustom();
}
}
}
private int tabSelectedHighColorSize = 4;
/// <summary>
/// 选中Tab页高亮高度
/// </summary>
[Description("选中Tab页高亮高度"), Category("SunnyUI")]
[DefaultValue(4)]
public int TabSelectedHighColorSize
{
get => tabSelectedHighColorSize;
set
{
value = Math.Max(value, 0);
value = Math.Min(value, 8);
tabSelectedHighColorSize = value;
Invalidate();
}
}
private UIStyle _style = UIStyle.Blue;
/// <summary>
/// 主题样式
/// </summary>
[DefaultValue(UIStyle.Blue), Description("主题样式"), Category("SunnyUI")]
public UIStyle Style
{
get => _style;
set => SetStyle(value);
}
[Browsable(false)]
public override Rectangle DisplayRectangle
{
get
{
Rectangle rect = base.DisplayRectangle;
if (tabVisible)
{
return new Rectangle(rect.Left - 4, rect.Top - 4, rect.Width + 8, rect.Height + 8);
}
else
{
return new Rectangle(rect.Left - 4, rect.Top - 5, rect.Width + 8, rect.Height + 9);
}
}
}
private void AfterSetFillColor(Color color)
{
foreach (TabPage page in TabPages)
{
page.BackColor = color;
}
}
public void SetStyle(UIStyle style)
{
if (!style.IsCustom())
{
SetStyleColor(style.Colors());
Invalidate();
}
_style = style;
}
public void SetStyleColor(UIBaseStyle uiColor)
{
tabSelectedForeColor = uiColor.TabControlTabSelectedColor;
tabSelectedHighColor = uiColor.TabControlTabSelectedColor;
_fillColor = uiColor.TabControlBackColor;
}
private UIMenuStyle _menuStyle = UIMenuStyle.Black;
[DefaultValue(UIMenuStyle.Black)]
[Description("主题风格"), Category("SunnyUI")]
public UIMenuStyle MenuStyle
{
get => _menuStyle;
set
{
if (value != UIMenuStyle.Custom)
{
SetMenuStyle(UIStyles.MenuColors[value]);
}
_menuStyle = value;
}
}
private void SetMenuStyle(UIMenuColor uiColor)
{
tabBackColor = uiColor.BackColor;
tabSelectedColor = uiColor.SelectedColor;
tabUnSelectedForeColor = uiColor.UnSelectedForeColor;
Invalidate();
}
protected override void CreateHandle()
{
base.CreateHandle();
DoubleBuffered = true;
SizeMode = TabSizeMode.Fixed;
Appearance = TabAppearance.Normal;
//Alignment = TabAlignment.Top;
}
private bool showCloseButton;
[DefaultValue(false), Description("所有Tab页面标题显示关闭按钮"), Category("SunnyUI")]
public bool ShowCloseButton
{
get => showCloseButton;
set
{
if (showCloseButton != value)
{
showCloseButton = value;
if (showActiveCloseButton) showActiveCloseButton = false;
Invalidate();
}
}
}
private bool showActiveCloseButton;
[DefaultValue(false), Description("当前激活的Tab页面标题显示关闭按钮"), Category("SunnyUI")]
public bool ShowActiveCloseButton
{
get => showActiveCloseButton;
set
{
if (showActiveCloseButton != value)
{
showActiveCloseButton = value;
if (showCloseButton) showCloseButton = false;
Invalidate();
}
}
}
private ConcurrentDictionary<int, bool> CloseRects = new ConcurrentDictionary<int, bool>();
/// <summary>
/// 重载绘图
/// </summary>
/// <param name="e">绘图参数</param>
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// 绘制背景色
e.Graphics.Clear(TabBackColor);
if (!TabVisible)
{
return;
}
for (int index = 0; index <= TabCount - 1; index++)
{
Rectangle TabRect = new Rectangle(GetTabRect(index).Location.X - 2, GetTabRect(index).Location.Y - 2, ItemSize.Width, ItemSize.Height);
if (Alignment == TabAlignment.Bottom)
{
TabRect = new Rectangle(GetTabRect(index).Location.X - 2, GetTabRect(index).Location.Y + 2, ItemSize.Width, ItemSize.Height);
}
Size sf = TextRenderer.MeasureText(TabPages[index].Text, Font);
int textLeft = ImageList?.ImageSize.Width ?? 0;
if (ImageList != null) textLeft += 4 + 4 + 6;
if (TextAlignment == HorizontalAlignment.Right)
textLeft = (int)(TabRect.Width - 4 - sf.Width);
if (TextAlignment == HorizontalAlignment.Center)
textLeft = textLeft + (int)((TabRect.Width - textLeft - sf.Width) / 2.0f);
// 绘制标题
e.Graphics.FillRectangle(tabBackColor, TabRect);
if (index == SelectedIndex)
{
e.Graphics.FillRectangle(TabSelectedColor, TabRect);
if (TabSelectedHighColorSize > 0)
e.Graphics.FillRectangle(TabSelectedHighColor, TabRect.Left, TabRect.Height - TabSelectedHighColorSize, TabRect.Width, TabSelectedHighColorSize);
}
e.Graphics.DrawString(TabPages[index].Text, Font, index == SelectedIndex ? tabSelectedForeColor : TabUnSelectedForeColor,
new Rectangle(TabRect.Left + textLeft, TabRect.Top, TabRect.Width, TabRect.Height), ContentAlignment.MiddleLeft);
var menuItem = Helper[index];
bool show1 = TabPages[index].Text != MainPage;
bool show2 = menuItem == null || !menuItem.AlwaysOpen;
bool showButton = show1 && show2;
if (showButton)
{
if (ShowCloseButton || (ShowActiveCloseButton && index == SelectedIndex))
{
Color color = TabUnSelectedForeColor;
if (CloseRects.ContainsKey(index) && CloseRects[index])
{
color = tabSelectedForeColor;
}
e.Graphics.DrawFontImage(77, 28, color, new Rectangle(TabRect.Left + TabRect.Width - 28, 0, 24, TabRect.Height));
}
}
// 绘制图标
if (ImageList != null)
{
int imageIndex = TabPages[index].ImageIndex;
if (imageIndex >= 0 && imageIndex < ImageList.Images.Count)
{
e.Graphics.DrawImage(ImageList.Images[imageIndex], TabRect.Left + 4 + 6, TabRect.Y + (TabRect.Height - ImageList.ImageSize.Height) / 2.0f, ImageList.ImageSize.Width, ImageList.ImageSize.Height);
}
}
string TipsText = GetTipsText(TabPages[index]);
if (Enabled && TipsText.IsValid())
{
using var TempFont = TipsFont.DPIScaleFont(TipsFont.Size);
sf = TextRenderer.MeasureText(TipsText, TempFont);
int sfMax = Math.Max(sf.Width, sf.Height);
int x = TabRect.Width - 1 - 2 - sfMax;
if (showActiveCloseButton || ShowCloseButton) x -= 24;
int y = 1 + 1;
e.Graphics.FillEllipse(TipsColor, TabRect.Left + x - 1, y, sfMax, sfMax);
e.Graphics.DrawString(TipsText, TempFont, TipsForeColor, new Rectangle(TabRect.Left + x, y, sfMax, sfMax), ContentAlignment.MiddleCenter);
}
}
}
/// <summary>
/// 重载鼠标移动事件
/// </summary>
/// <param name="e">鼠标参数</param>
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (ShowActiveCloseButton || ShowCloseButton)
{
for (int index = 0; index <= TabCount - 1; index++)
{
Rectangle TabRect = new Rectangle(GetTabRect(index).Location.X - 2, GetTabRect(index).Location.Y - 2, ItemSize.Width, ItemSize.Height);
Rectangle closeRect = new Rectangle(TabRect.Right - 28, 0, 28, TabRect.Height);
bool inrect = e.Location.InRect(closeRect);
if (!CloseRects.ContainsKey(index))
CloseRects.TryAdd(index, false);
if (inrect != CloseRects[index])
{
CloseRects[index] = inrect;
Invalidate();
}
}
}
}
/// <summary>
/// 重载鼠标按下事件
/// </summary>
/// <param name="e">鼠标参数</param>
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
int removeIndex = -1;
for (int index = 0; index <= TabCount - 1; index++)
{
Rectangle TabRect = new Rectangle(GetTabRect(index).Location.X - 2, GetTabRect(index).Location.Y - 2, ItemSize.Width, ItemSize.Height);
Rectangle rect = new Rectangle(TabRect.Right - 28, TabRect.Top, 24, TabRect.Height);
if (e.Location.InRect(rect))
{
removeIndex = index;
break;
}
}
if (removeIndex < 0 || removeIndex >= TabCount)
{
return;
}
var menuItem = Helper[removeIndex];
bool show1 = TabPages[removeIndex].Text != MainPage;
bool show2 = menuItem == null || !menuItem.AlwaysOpen;
bool showButton = show1 && show2;
if (showButton)
{
if (ShowCloseButton)
{
if (BeforeRemoveTabPage == null || BeforeRemoveTabPage.Invoke(this, removeIndex))
{
RemoveTabPage(removeIndex);
}
}
else if (ShowActiveCloseButton && removeIndex == SelectedIndex)
{
if (DrawedIndex == removeIndex)
{
if (BeforeRemoveTabPage == null || BeforeRemoveTabPage.Invoke(this, removeIndex))
{
RemoveTabPage(removeIndex);
}
}
}
}
}
public delegate bool OnBeforeRemoveTabPage(object sender, int index);
public delegate void OnAfterRemoveTabPage(object sender, int index);
public event OnBeforeRemoveTabPage BeforeRemoveTabPage;
public event OnAfterRemoveTabPage AfterRemoveTabPage;
[DefaultValue(true)]
[Description("多页面框架时包含UIPage在点击Tab页关闭时关闭UIPage"), Category("SunnyUI")]
public bool AutoClosePage
{
get; set;
}
[DefaultValue(true)]
[Description("移除TabPage后是否自动销毁TabPage"), Category("SunnyUI")]
public bool DisposeTabPageAfterRemove
{
get; set;
}
internal void RemoveTabPage(int index)
{
if (index < 0 || index >= TabCount)
{
return;
}
TabPage tabPage = TabPages[index];
var pages = tabPage.GetControls<UIPage>();
for (int i = 0; i < pages.Count; i++)
{
if (AutoClosePage)
{
PageRemoved?.Invoke(this, new UIPageEventArgs(pages[i]));
try
{
pages[i].Final();
pages[i].Close();
pages[i].Dispose();
pages[i] = null;
}
catch
{ }
}
else
{
pages[i].Parent = null;
}
}
if (TabCount > 1 && index > 0)
{
SelectedTab = TabPages[index - 1];
}
TabPages.Remove(tabPage);
AfterRemoveTabPage?.Invoke(this, index);
//if (TabCount > 0)
//{
// if (index == 0) SelectedIndex = 0;
// if (index > 0) SelectedIndex = index - 1;
//}
if (DisposeTabPageAfterRemove) tabPage.Dispose();
}
public enum UITabPosition
{
Left,
Right
}
[DefaultValue(UITabPosition.Left)]
[Description("标签页显示位置"), Category("SunnyUI")]
public UITabPosition TabPosition
{
get => (RightToLeftLayout && RightToLeft == RightToLeft.Yes)
? UITabPosition.Right
: UITabPosition.Left;
set
{
RightToLeftLayout = value == UITabPosition.Right;
RightToLeft = (value == UITabPosition.Right) ? RightToLeft.Yes : RightToLeft.No;
}
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
CloseRects.Clear();
Init();
if (ShowActiveCloseButton && !ShowCloseButton)
{
timer.Start();
}
}
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
timer?.Start();
}
//private int LastIndex;
public void Init()
{
if (SelectedIndex < 0 || SelectedIndex >= TabPages.Count)
{
return;
}
if (SelectedIndex >= 0)
{
List<UIPage> pages = TabPages[SelectedIndex].GetControls<UIPage>();
foreach (var page in pages)
{
page.ReLoad();
}
}
List<UITabControlMenu> leftTabControls = TabPages[SelectedIndex].GetControls<UITabControlMenu>();
foreach (var tabControl in leftTabControls)
{
tabControl.Init();
}
List<UITabControl> topTabControls = TabPages[SelectedIndex].GetControls<UITabControl>();
foreach (var tabControl in topTabControls)
{
tabControl.Init();
}
}
internal IntPtr UpDownButtonHandle => FindUpDownButton();
private IntPtr FindUpDownButton()
{
return User.FindWindowEx(Handle, IntPtr.Zero, UpDownButtonClassName, null).IntPtr();
}
public void OnPaintUpDownButton(UpDownButtonPaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rect = e.ClipRectangle;
Color upButtonArrowColor = tabUnSelectedForeColor;
Color downButtonArrowColor = tabUnSelectedForeColor;
Rectangle upButtonRect = rect;
upButtonRect.X = 0;
upButtonRect.Y = 0;
upButtonRect.Width = rect.Width / 2 - 1;
upButtonRect.Height -= 1;
Rectangle downButtonRect = rect;
downButtonRect.X = upButtonRect.Right + 1;
downButtonRect.Y = 0;
downButtonRect.Width = rect.Width / 2 - 1;
downButtonRect.Height -= 1;
g.Clear(tabBackColor);
if (Enabled)
{
if (e.MouseOver)
{
if (e.MousePress)
{
//鼠标按下
if (e.MouseInUpButton)
upButtonArrowColor = Color.FromArgb(200, TabSelectedHighColor);
else
downButtonArrowColor = Color.FromArgb(200, TabSelectedHighColor);
}
else
{
//鼠标移动
if (e.MouseInUpButton)
upButtonArrowColor = TabSelectedHighColor;
else
downButtonArrowColor = TabSelectedHighColor;
}
}
}
else
{
upButtonArrowColor = SystemColors.ControlDark;
downButtonArrowColor = SystemColors.ControlDark;
}
g.SmoothingMode = SmoothingMode.AntiAlias;
RenderButton(g, upButtonRect, upButtonArrowColor, ArrowDirection.Left);
RenderButton(g, downButtonRect, downButtonArrowColor, ArrowDirection.Right);
UpDownButtonPaintEventHandler handler = Events[EventPaintUpDownButton] as UpDownButtonPaintEventHandler;
handler?.Invoke(this, e);
}
private static void RenderButton(Graphics g, Rectangle rect, Color arrowColor, ArrowDirection direction)
{
switch (direction)
{
case ArrowDirection.Left:
g.DrawFontImage(61700, 24, arrowColor, rect);
break;
case ArrowDirection.Right:
g.DrawFontImage(61701, 24, arrowColor, rect, 1);
break;
}
}
private static readonly object EventPaintUpDownButton = new object();
private const string UpDownButtonClassName = "msctls_updown32";
private UpDownButtonNativeWindow _upDownButtonNativeWindow;
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if (UpDownButtonHandle != IntPtr.Zero)
{
if (_upDownButtonNativeWindow == null)
{
_upDownButtonNativeWindow = new UpDownButtonNativeWindow(this);
}
}
}
protected override void OnCreateControl()
{
base.OnCreateControl();
if (UpDownButtonHandle != IntPtr.Zero)
{
if (_upDownButtonNativeWindow == null)
{
_upDownButtonNativeWindow = new UpDownButtonNativeWindow(this);
}
}
}
protected override void OnHandleDestroyed(EventArgs e)
{
base.OnHandleDestroyed(e);
if (_upDownButtonNativeWindow != null)
{
_upDownButtonNativeWindow.Dispose();
_upDownButtonNativeWindow = null;
}
}
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (UpDownButtonHandle != IntPtr.Zero)
{
if (_upDownButtonNativeWindow == null)
{
_upDownButtonNativeWindow = new UpDownButtonNativeWindow(this);
}
}
if (e.Control is TabPage)
{
e.Control.Padding = new Padding(0);
if (ShowActiveCloseButton && !ShowCloseButton)
{
timer.Start();
}
}
}
/// <summary>
/// 重载控件尺寸变更
/// </summary>
/// <param name="e">参数</param>
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
if (UpDownButtonHandle != IntPtr.Zero)
{
if (_upDownButtonNativeWindow == null)
{
_upDownButtonNativeWindow = new UpDownButtonNativeWindow(this);
}
}
}
private class UpDownButtonNativeWindow : NativeWindow, IDisposable
{
private UITabControl _owner;
private bool _bPainting;
private Rectangle clipRect;
public UpDownButtonNativeWindow(UITabControl owner)
{
_owner = owner;
AssignHandle(owner.UpDownButtonHandle);
}
private static bool LeftKeyPressed()
{
if (SystemInformation.MouseButtonsSwapped)
{
return (User.GetKeyState(User.VK_RBUTTON) < 0);
}
return (User.GetKeyState(User.VK_LBUTTON) < 0);
}
private void DrawUpDownButton()
{
RECT rect = new RECT();
bool mousePress = LeftKeyPressed();
Point cursorPoint = SystemEx.GetCursorPos();
User.GetWindowRect(Handle, ref rect);
var mouseOver = User.PtInRect(ref rect, cursorPoint);
cursorPoint.X -= rect.Left;
cursorPoint.Y -= rect.Top;
var mouseInUpButton = cursorPoint.X < clipRect.Width / 2;
using (Graphics g = Graphics.FromHwnd(Handle))
{
UpDownButtonPaintEventArgs e = new UpDownButtonPaintEventArgs(g, clipRect, mouseOver, mousePress, mouseInUpButton);
_owner.OnPaintUpDownButton(e);
}
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case User.WM_PAINT:
if (!_bPainting)
{
int itemTop = 0;
if (_owner.Alignment == TabAlignment.Top)
{
itemTop = 0;
}
else if (_owner.Alignment == TabAlignment.Bottom)
{
itemTop = _owner.Size.Height - _owner.ItemSize.Height;
}
Point UpDownButtonLocation = new Point(_owner.Size.Width - 52, itemTop);
Size UpDownButtonSize = new Size(52, _owner.ItemSize.Height);
clipRect = new Rectangle(UpDownButtonLocation, UpDownButtonSize);
User.MoveWindow(Handle, UpDownButtonLocation.X, UpDownButtonLocation.Y, clipRect.Width, clipRect.Height);
PAINTSTRUCT ps = new PAINTSTRUCT();
_bPainting = true;
User.BeginPaint(m.HWnd, ref ps);
DrawUpDownButton();
User.EndPaint(m.HWnd, ref ps);
_bPainting = false;
m.Result = Win32Helper.TRUE;
}
else
{
base.WndProc(ref m);
}
break;
default:
base.WndProc(ref m);
break;
}
}
#region IDisposable
/// <summary>
/// 析构函数
/// </summary>
public void Dispose()
{
_owner = null;
base.ReleaseHandle();
}
#endregion IDisposable
}
public delegate void UpDownButtonPaintEventHandler(object sender, UpDownButtonPaintEventArgs e);
public class UpDownButtonPaintEventArgs : PaintEventArgs
{
public UpDownButtonPaintEventArgs(
Graphics graphics,
Rectangle clipRect,
bool mouseOver,
bool mousePress,
bool mouseInUpButton)
: base(graphics, clipRect)
{
MouseOver = mouseOver;
MousePress = mousePress;
MouseInUpButton = mouseInUpButton;
}
public bool MouseOver
{
get;
}
public bool MousePress
{
get;
}
public bool MouseInUpButton
{
get;
}
}
}
}