灰姑娘本身也有自已的優點,但是卻可能因為外貌不討人喜歡,要變成白雪公主卻需要有很多勇氣和決心去改變自已:
- 有一顆善良的心
- 討人喜愛的外貌
我這里講的是一個工具條的蛻變過程,用”灰姑娘到白雪公主蛻變”這個比喻不知道是否合理?還懇請高人討教。
工具條控件提供了一種類似Outlook方式的導航菜單,用來切換各種業務窗口,用上這個控件,肯定為你的程序增色不少,這個工具條的優點是可以上下划動,很靈活,這個是我需要采用的;
缺點是只能跟傳統的系統界面進行匹配,提供外接設置的接口比較少,並且它沒有任何的換膚功能, 如果用到具有換膚功能的系統中,它真變成了“土里土氣的灰姑娘”。
現狀
現在來看傳統的OutLookBar的長相,是不是有些土里土氣?
蛻變后
現在我要讓它變成白雪公主,對它進行改造,添加支持換膚功能(背景色根據需要設置)...這樣就秀氣多了, 來看它的蛻變過程,如下:
(1)Office2007Blue:
文字中間對齊,Office鼠標經過效果:
文字向左對齊,Office鼠標經過效果:
Office鼠標經過效果:
另一種背景色,這個可以通過設置調整:
鼠標點下時效果:
(2)Office2007Silver:
鼠標經過時效果:
正常狀態:
如何蛻變?
另一種OutLook的效果,它做得非常漂亮,請參考網站 www.codeproject.com上的一篇介紹OutLook樣式的導航條的文章《A Serious Outlook Style Navigation Pane Control》,具體圖示:
正常效果 鼠標經過效果 鼠標點擊效果
它的兩種樣式:
Office2007Blue:
Office2007Silver:
這個控件的優點很明顯:很清新,美觀,也靈活;至於缺點,我總感覺它不能夠上下划動,拉動時划動距離還是有限的,個人總感覺還是我前面提到的那種上下划動比較靈活。
所以,我根據這個控件的設計原理,對前面講到的能上下划動的工具條控件做改善。
新特性:
- 添加換膚接口,能夠靈活擴展皮膚模板
- 添加鼠標經過,按下(hover,Press)導航按鈕時Office效果
具體設計步驟:
-
設計一個基本皮膚模板類:NaviColorTableOffice.cs
參考源碼:
using System; using System.Collections.Generic; using System.Drawing; using System.Text; namespace UtilityLibrary.Common { public class NaviColorTableOffice { // General colors public virtual Color DarkBorder { get { return Color.FromArgb(101, 147, 207); } } public virtual Color Text { get { return Color.FromArgb(21, 66, 139); } } public virtual Color Background { get { return Color.FromArgb(255, 255, 255); } } public virtual Color ShapesFront { get { return Color.FromArgb(86, 125, 177); } } // NaviButton Normal public virtual Color ButtonLight { get { return Color.FromArgb(192, 219, 255); } } public virtual Color ButtonDark { get { return Color.FromArgb(173, 209, 255); } } public virtual Color ButtonHighlightDark { get { return Color.FromArgb(196, 221, 255); } } public virtual Color ButtonHighlightLight { get { return Color.FromArgb(227, 239, 255); } } // NaviButton hovered public virtual Color ButtonHoveredLight { get { return Color.FromArgb(255, 230, 159); } } public virtual Color ButtonHoveredDark { get { return Color.FromArgb(255, 215, 103); } } public virtual Color ButtonHoveredHighlightDark { get { return Color.FromArgb(255, 233, 168); } } public virtual Color ButtonHoveredHighlightLight { get { return Color.FromArgb(255, 254, 228); } } // NaviButton active public virtual Color ButtonActiveLight { get { return Color.FromArgb(254, 225, 122); } } public virtual Color ButtonActiveDark { get { return Color.FromArgb(255, 171, 63); } } public virtual Color ButtonActiveHighlightDark { get { return Color.FromArgb(255, 188, 111); } } public virtual Color ButtonActiveHighlightLight { get { return Color.FromArgb(255, 217, 170); } } // NaviButton clicked public virtual Color ButtonClickedLight { get { return Color.FromArgb(255, 211, 101); } } public virtual Color ButtonClickedDark { get { return Color.FromArgb(251, 140, 60); } } public virtual Color ButtonClickedHighlightDark { get { return Color.FromArgb(255, 173, 67); } } public virtual Color ButtonClickedHighlightLight { get { return Color.FromArgb(255, 189, 105); } } // Popuped band backcolor public virtual Color PopupBandBackground { get { return Color.FromArgb(227, 239, 255); } } // Splitter public virtual Color SplitterDark { get { return Color.FromArgb(182, 214, 255); } } public virtual Color SplitterLight { get { return Color.FromArgb(255, 255, 255); } } public virtual Color SplitterHighlights { get { return Color.FromArgb(255, 255, 255); } } // Options button public virtual Color ButtonOptionsOuter { get { return Color.FromArgb(67, 113, 176); } } public virtual Color ButtonOptionsInner { get { return Color.FromArgb(255, 248, 203); } } // Header of band public virtual Color HeaderBgDark { get { return Color.FromArgb(175, 210, 255); } } public virtual Color HeaderBgLight { get { return Color.FromArgb(227, 239, 255); } } public virtual Color HeaderBgInnerBorder { get { return Color.FromArgb(255, 255, 255); } } // Group public virtual Color GroupBgLight { get { return Color.FromArgb(226, 238, 255); } } public virtual Color GroupBgDark { get { return Color.FromArgb(214, 232, 255); } } public virtual Color GroupBgHoveredLight { get { return Color.FromArgb(255, 255, 255); } } public virtual Color GroupBgHoveredDark { get { return Color.FromArgb(227, 239, 255); } } public virtual Color GroupBorderLight { get { return Color.FromArgb(173, 209, 255); } } public virtual Color GroupInnerBorder { get { return Color.FromArgb(255, 255, 255); } } // Collapse button public virtual Color CollapseButtonHoveredDark { get { return Color.FromArgb(248, 194, 94); } } public virtual Color CollapseButtonHoveredLight { get { return Color.FromArgb(255, 255, 220); } } public virtual Color CollapseButtonDownDark { get { return Color.FromArgb(232, 127, 8); } } public virtual Color CollapseButtonDownLight { get { return Color.FromArgb(247, 217, 121); } } // Collapsed band public virtual Color BandCollapsedBg { get { return Color.FromArgb(213, 228, 242); } } public virtual Color BandCollapsedFocused { get { return Color.FromArgb(255, 231, 162); } } public virtual Color BandCollapsedClicked { get { return Color.FromArgb(251, 140, 60); } } // Groupview public virtual Color DashedLineColor { get { return Color.FromArgb(194, 194, 194); } } } }
2. 再做幾個模板,繼承皮膚基本類NaviColorTableOffice
(1). Office2007Blue
using System; using System.Collections.Generic; using System.Drawing; using System.Text; namespace UtilityLibrary.Common { public class NaviColorTableOffice2007Blue : NaviColorTableOffice { // General colors public virtual Color DarkBorder { get { return Color.FromArgb(101, 147, 207); } } public virtual Color Text { get { return Color.FromArgb(21, 66, 139); } } public virtual Color Background { get { return Color.FromArgb(255, 255, 255); } } public virtual Color ShapesFront { get { return Color.FromArgb(86, 125, 177); } } // NaviButton Normal public virtual Color ButtonLight { get { return Color.FromArgb(192, 219, 255); } } public virtual Color ButtonDark { get { return Color.FromArgb(173, 209, 255); } } public virtual Color ButtonHighlightDark { get { return Color.FromArgb(196, 221, 255); } } public virtual Color ButtonHighlightLight { get { return Color.FromArgb(227, 239, 255); } } // NaviButton hovered public virtual Color ButtonHoveredLight { get { return Color.FromArgb(255, 230, 159); } } public virtual Color ButtonHoveredDark { get { return Color.FromArgb(255, 215, 103); } } public virtual Color ButtonHoveredHighlightDark { get { return Color.FromArgb(255, 233, 168); } } public virtual Color ButtonHoveredHighlightLight { get { return Color.FromArgb(255, 254, 228); } } // NaviButton active public virtual Color ButtonActiveLight { get { return Color.FromArgb(254, 225, 122); } } public virtual Color ButtonActiveDark { get { return Color.FromArgb(255, 171, 63); } } public virtual Color ButtonActiveHighlightDark { get { return Color.FromArgb(255, 188, 111); } } public virtual Color ButtonActiveHighlightLight { get { return Color.FromArgb(255, 217, 170); } } // NaviButton clicked public virtual Color ButtonClickedLight { get { return Color.FromArgb(255, 211, 101); } } public virtual Color ButtonClickedDark { get { return Color.FromArgb(251, 140, 60); } } public virtual Color ButtonClickedHighlightDark { get { return Color.FromArgb(255, 173, 67); } } public virtual Color ButtonClickedHighlightLight { get { return Color.FromArgb(255, 189, 105); } } // Popuped band backcolor public virtual Color PopupBandBackground { get { return Color.FromArgb(227, 239, 255); } } // Splitter public virtual Color SplitterDark { get { return Color.FromArgb(182, 214, 255); } } public virtual Color SplitterLight { get { return Color.FromArgb(255, 255, 255); } } public virtual Color SplitterHighlights { get { return Color.FromArgb(255, 255, 255); } } // Options button public virtual Color ButtonOptionsOuter { get { return Color.FromArgb(67, 113, 176); } } public virtual Color ButtonOptionsInner { get { return Color.FromArgb(255, 248, 203); } } // Header of band public virtual Color HeaderBgDark { get { return Color.FromArgb(175, 210, 255); } } public virtual Color HeaderBgLight { get { return Color.FromArgb(227, 239, 255); } } public virtual Color HeaderBgInnerBorder { get { return Color.FromArgb(255, 255, 255); } } // Group public virtual Color GroupBgLight { get { return Color.FromArgb(226, 238, 255); } } public virtual Color GroupBgDark { get { return Color.FromArgb(214, 232, 255); } } public virtual Color GroupBgHoveredLight { get { return Color.FromArgb(255, 255, 255); } } public virtual Color GroupBgHoveredDark { get { return Color.FromArgb(227, 239, 255); } } public virtual Color GroupBorderLight { get { return Color.FromArgb(173, 209, 255); } } public virtual Color GroupInnerBorder { get { return Color.FromArgb(255, 255, 255); } } // Collapse button public virtual Color CollapseButtonHoveredDark { get { return Color.FromArgb(248, 194, 94); } } public virtual Color CollapseButtonHoveredLight { get { return Color.FromArgb(255, 255, 220); } } public virtual Color CollapseButtonDownDark { get { return Color.FromArgb(232, 127, 8); } } public virtual Color CollapseButtonDownLight { get { return Color.FromArgb(247, 217, 121); } } // Collapsed band public virtual Color BandCollapsedBg { get { return Color.FromArgb(213, 228, 242); } } public virtual Color BandCollapsedFocused { get { return Color.FromArgb(255, 231, 162); } } public virtual Color BandCollapsedClicked { get { return Color.FromArgb(251, 140, 60); } } // Groupview public virtual Color DashedLineColor { get { return Color.FromArgb(194, 194, 194); } } } }
(2). Office2007Silver
using System.Drawing; namespace UtilityLibrary.Common { public class NaviColorTableOffice2007Silver : NaviColorTableOffice { // General colors public override Color DarkBorder { get { return Color.FromArgb(111, 112, 116); } } public override Color Text { get { return Color.FromArgb(21, 66, 139); } } public override Color ShapesFront { get { return Color.FromArgb(101, 104, 112); } } // NaviButton Normal public override Color ButtonLight { get { return Color.FromArgb(219, 222, 226); } } public override Color ButtonDark { get { return Color.FromArgb(197, 199, 209); } } public override Color ButtonHighlightDark { get { return Color.FromArgb(214, 218, 228); } } public override Color ButtonHighlightLight { get { return Color.FromArgb(235, 238, 250); } } // Header of band public override Color HeaderBgDark { get { return Color.FromArgb(218, 223, 230); } } public override Color HeaderBgLight { get { return Color.FromArgb(255, 255, 255); } } // Splitter public override Color SplitterDark { get { return Color.FromArgb(119, 118, 151); } } public override Color SplitterLight { get { return Color.FromArgb(168, 167, 191); } } public override Color SplitterHighlights { get { return Color.FromArgb(255, 255, 255); } } // Group public override Color GroupBgLight { get { return Color.FromArgb(215, 215, 229); } } public override Color GroupBgDark { get { return Color.FromArgb(216, 216, 230); } } public override Color GroupBgHoveredLight { get { return Color.FromArgb(215, 215, 229); } } public override Color GroupBgHoveredDark { get { return Color.FromArgb(216, 216, 230); } } public override Color GroupBorderLight { get { return Color.FromArgb(197, 199, 199); } } // Collapsed band public override Color BandCollapsedBg { get { return Color.FromArgb(238, 238, 244); } } public override Color PopupBandBackground { get { return Color.FromArgb(240, 241, 242); } } } }
(3). Office2007Black
using System.Drawing; namespace UtilityLibrary.Common { public class NaviColorTableOffice2007Black : NaviColorTableOffice { // General colors public override Color DarkBorder { get { return Color.FromArgb(167, 173, 182); } } public override Color Text { get { return Color.FromArgb(0, 0, 0); } } public override Color ShapesFront { get { return Color.FromArgb(49, 52, 49); } } // NaviButton Normal public override Color ButtonLight { get { return Color.FromArgb(219, 222, 226); } } //public override Color ButtonDark { get { return Color.FromArgb(199, 203, 209); } } public override Color ButtonDark { get { return Color.Silver; } } public override Color ButtonHighlightDark { get { return Color.FromArgb(223, 226, 228); } } public override Color ButtonHighlightLight { get { return Color.FromArgb(248, 248, 249); } } // Header of band public override Color HeaderBgDark { get { return Color.FromArgb(189, 193, 200); } } public override Color HeaderBgLight { get { return Color.FromArgb(240, 241, 242); } } // Splitter public override Color SplitterDark { get { return Color.FromArgb(195, 200, 206); } } public override Color SplitterLight { get { return Color.FromArgb(255, 255, 255); } } public override Color SplitterHighlights { get { return Color.FromArgb(255, 255, 255); } } // Group public override Color GroupBgLight { get { return Color.FromArgb(239, 240, 241); } } public override Color GroupBgDark { get { return Color.FromArgb(221, 224, 227); } } public override Color GroupBgHoveredLight { get { return Color.FromArgb(255, 255, 255); } } public override Color GroupBgHoveredDark { get { return Color.FromArgb(232, 234, 236); } } public override Color GroupBorderLight { get { return Color.FromArgb(199, 203, 209); } } public override Color GroupInnerBorder { get { return Color.FromArgb(255, 255, 255); } } // Collapsed band public override Color BandCollapsedBg { get { return Color.FromArgb(235, 235, 235); } } public override Color PopupBandBackground { get { return Color.FromArgb(240, 241, 242); } } } }
(4). 如何去實現渲染這個工具欄上的按鈕,把它們加工得更漂亮一點?
我是這樣做的,設計一對控件進行渲染的類:NaviButtonRendererOffice2007.cs,由它來實現對控件進行重加工,參考如下:
using System; using System.Collections.Generic; using System.Drawing; using System.Text; using System.Windows.Forms; namespace UtilityLibrary.Common { public class NaviButtonRendererOffice2007 { NaviColorTableOffice colorTable; public NaviButtonRendererOffice2007() { // Use by default the blue colors, override this with the property ColorTable colorTable = new NaviColorTableOffice2007Blue(); } /// <summary> /// Gets or sets the table of colors /// </summary> public NaviColorTableOffice ColorTable { get { return colorTable; } set { colorTable = value; } } /// <summary> /// Draws the background gradients of an Button /// </summary> /// <param name="g">The graphics surface to draw on</param> /// <param name="bounds">The bounds that the drawing should apply to</param> public void DrawBackground(Graphics g, Rectangle bounds, ControlState state, InputState inputState) { Color[] endColors = new Color[1]; if ((state == ControlState.Normal) && (inputState == InputState.Normal)) { endColors = new Color[] { ColorTable.ButtonLight, ColorTable.ButtonDark, ColorTable.ButtonHighlightDark, ColorTable.ButtonHighlightLight }; } else if ((state == ControlState.Normal) && (inputState == InputState.Hovered)) { endColors = new Color[] { ColorTable.ButtonHoveredLight, ColorTable.ButtonHoveredDark, ColorTable.ButtonHoveredHighlightDark, ColorTable.ButtonHoveredHighlightLight }; } else if ((state == ControlState.Active) && (inputState == InputState.Normal)) { endColors = new Color[] { ColorTable.ButtonActiveLight, ColorTable.ButtonActiveDark, ColorTable.ButtonActiveHighlightDark, ColorTable.ButtonActiveHighlightLight }; } else if ((inputState == InputState.Clicked) || ((state == ControlState.Active) && (inputState == InputState.Hovered))) { endColors = new Color[] { ColorTable.ButtonClickedLight, ColorTable.ButtonClickedDark, ColorTable.ButtonClickedHighlightDark, ColorTable.ButtonClickedHighlightLight }; } float[] ColorPositions = { 0.0f, 0.62f, 0.62f, 1.0f }; ExtDrawing.DrawGradient(g, bounds, endColors, ColorPositions); using (Pen p = new Pen(ColorTable.DarkBorder)) { g.DrawLine(p, bounds.Left, bounds.Top, bounds.Right, bounds.Top); } } /// <summary> /// Draws text on a graphics canvas /// </summary> /// <param name="g">The graphics surface to draw on</param> /// <param name="bounds">The bounds of the text</param> /// <param name="font">The font of the text</param> /// <param name="text">The text to draw</param> /// <param name="rightToLeft">Rigth to left or left to right layout</param> public void DrawText(Graphics g, Rectangle bounds, Font font, string text, bool rightToLeft) { using (Brush brush = new SolidBrush(ColorTable.Text)) { if (rightToLeft) { TextRenderer.DrawText(g, text, font, bounds, ColorTable.Text, TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis | TextFormatFlags.Right | TextFormatFlags.RightToLeft); } else { TextRenderer.DrawText(g, text, font, bounds, ColorTable.Text, TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis); } } } } }
我們直接調DrawBackground(Graphics g, Rectangle bounds, ControlState state, InputState inputState) 對按鈕進行重繪就可以實現了。
那么如何達到換膚的功能?關鍵是對象NaviColorTableOffice,其他的皮膚類都繼承它,這里是通過多態的方式進行實例化對象。
請參考StyleManager.cs,這是一個皮膚制造工廠,通過反射機制去動態實例化皮膚對象:
using System; using System.Collections.Generic; using System.Text; using UtilityLibrary.Enums; namespace UtilityLibrary.Common { class StyleManager { public static NaviColorTableOffice GetOffice2007ColorTable(Style style) { string className = "UtilityLibrary.Common.NaviColorTable" + style.ToString(); Type type = Type.GetType(className); if (type != null) { return (NaviColorTableOffice)Activator.CreateInstance(type); } return null; } } }
我添加一個enum類型作為皮膚的樣式,這里只設計三個樣式。
namespace UtilityLibrary.Enums { public enum Style { Office2007Blue, Office2007Silver, Office2007Black } }
最后關鍵的一步到了,在OutlookBar.cs實現接口IStyle:
#region OutlookBar class [ToolboxBitmap(typeof(UtilityLibrary.WinControls.OutlookBar), "UtilityLibrary.WinControls.OutlookBar.bmp")] public class OutlookBar : System.Windows.Forms.Control,IStyle {
}
如下代碼是客戶端設置皮膚的關鍵:
#region IStyle 成員 public void SetStyle(Style style) { rendererOffice2007.ColorTable = StyleManager.GetOffice2007ColorTable(style); this.Refresh(); } private Style _style = Style.Office2007Blue; public Style Style { get { return _style; } set { _style = value; SetStyle(_style); } }
所以我們在客戶端設計某個皮膚時,可以這樣做:
OutlookBar outlookBar1 = new OutlookBar(); outlookBar1.SetStyle(Style.Office2007Blue);//設置Office2007Blue皮膚 outlookBar1.OfficeStyle = true;//設置Office效果,主要是mouse經過,點下時的效果
最終的整體效果
總結
整個過程下來,主要做的工作:
-
設計模板
-
設計換膚接口
-
渲染按鈕控件
-
換膚接口調用
經過這幾個工序,對這個灰姑娘進行“整容”,“美化”的一系列過程,它就變成了白雪公主啦,不過因為它先天不足,只能說差不多過得去。
上傳改善后的控件供大家試用吧,分享快樂,如果感覺比原來的好,記得給小弟點評一下喔~~~