├── README.md ├── LICENSE ├── MenuColorTable.cs ├── MenuRenderer.cs └── RJDropdownMenu.cs /README.md: -------------------------------------------------------------------------------- 1 | # Dropdown-Menu-CSharp-WinForms 2 | How to create a Dropdown Menu (Custom ContextMenuStrip) with C# and Windows Forms. 3 | 4 |

VIDEO:

5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /MenuColorTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | using System.Drawing; 8 | 9 | namespace CustomControls.RJControls 10 | { 11 | public class MenuColorTable : ProfessionalColorTable 12 | { 13 | //Fields 14 | private Color backColor; 15 | private Color leftColumnColor; 16 | private Color borderColor; 17 | private Color menuItemBorderColor; 18 | private Color menuItemSelectedColor; 19 | 20 | //Constructor 21 | public MenuColorTable(bool isMainMenu, Color primaryColor) 22 | { 23 | if (isMainMenu) 24 | { 25 | backColor = Color.FromArgb(37, 39, 60); 26 | leftColumnColor = Color.FromArgb(32, 33, 51); 27 | borderColor = Color.FromArgb(32, 33, 51); 28 | menuItemBorderColor = primaryColor; 29 | menuItemSelectedColor = primaryColor; 30 | } 31 | else 32 | { 33 | backColor = Color.White; 34 | leftColumnColor = Color.LightGray; 35 | borderColor = Color.LightGray; 36 | menuItemBorderColor = primaryColor; 37 | menuItemSelectedColor = primaryColor; 38 | } 39 | } 40 | 41 | //Overrides 42 | public override Color ToolStripDropDownBackground { get { return backColor; } } 43 | public override Color MenuBorder { get { return borderColor; } } 44 | public override Color MenuItemBorder { get { return menuItemBorderColor; } } 45 | public override Color MenuItemSelected { get { return menuItemSelectedColor; } } 46 | public override Color ImageMarginGradientBegin { get { return leftColumnColor; } } 47 | public override Color ImageMarginGradientMiddle { get { return leftColumnColor; } } 48 | public override Color ImageMarginGradientEnd { get { return leftColumnColor; } } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /MenuRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | using System.Drawing; 8 | using System.Drawing.Drawing2D; 9 | 10 | namespace CustomControls.RJControls 11 | { 12 | public class MenuRenderer : ToolStripProfessionalRenderer 13 | { 14 | //Fields 15 | private Color primaryColor; 16 | private Color textColor; 17 | private int arrowThickness; 18 | 19 | //Constructor 20 | public MenuRenderer(bool isMainMenu, Color primaryColor, Color textColor) 21 | : base(new MenuColorTable(isMainMenu, primaryColor)) 22 | { 23 | this.primaryColor = primaryColor; 24 | if (isMainMenu) 25 | { 26 | arrowThickness = 3; 27 | if (textColor == Color.Empty) //Set Default Color 28 | this.textColor = Color.Gainsboro; 29 | else//Set custom text color 30 | this.textColor = textColor; 31 | } 32 | else 33 | { 34 | arrowThickness = 2; 35 | if (textColor == Color.Empty) //Set Default Color 36 | this.textColor = Color.DimGray; 37 | else//Set custom text color 38 | this.textColor = textColor; 39 | } 40 | } 41 | 42 | //Overrides 43 | protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e) 44 | { 45 | base.OnRenderItemText(e); 46 | e.Item.ForeColor = e.Item.Selected ? Color.White : textColor; 47 | } 48 | 49 | protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e) 50 | { 51 | //Fields 52 | var graph = e.Graphics; 53 | var arrowSize = new Size(5, 12); 54 | var arrowColor = e.Item.Selected ? Color.White : primaryColor; 55 | var rect = new Rectangle(e.ArrowRectangle.Location.X, (e.ArrowRectangle.Height - arrowSize.Height) / 2, 56 | arrowSize.Width, arrowSize.Height); 57 | using (GraphicsPath path = new GraphicsPath()) 58 | using (Pen pen = new Pen(arrowColor, arrowThickness)) 59 | { 60 | //Drawing 61 | graph.SmoothingMode = SmoothingMode.AntiAlias; 62 | path.AddLine(rect.Left, rect.Top, rect.Right, rect.Top + rect.Height / 2); 63 | path.AddLine(rect.Right, rect.Top + rect.Height / 2, rect.Left, rect.Top + rect.Height); 64 | graph.DrawPath(pen, path); 65 | } 66 | } 67 | 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /RJDropdownMenu.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using System.Windows.Forms; 8 | using System.Drawing; 9 | using System.Drawing.Drawing2D; 10 | using System.ComponentModel; 11 | 12 | namespace CustomControls.RJControls 13 | { 14 | public class RJDropdownMenu : ContextMenuStrip 15 | { 16 | //Fields 17 | private bool isMainMenu; 18 | private int menuItemHeight = 25; 19 | private Color menuItemTextColor = Color.Empty;//No color, The default color is set in the MenuRenderer class 20 | private Color primaryColor = Color.Empty;//No color, The default color is set in the MenuRenderer class 21 | 22 | private Bitmap menuItemHeaderSize; 23 | 24 | //Constructor 25 | public RJDropdownMenu(IContainer container) 26 | : base(container) 27 | { 28 | 29 | } 30 | 31 | //Properties 32 | //Optionally, hide the properties in the toolbox to avoid the problem of displaying and/or 33 | //saving control property changes in the designer at design time in Visual Studio. 34 | //If the problem I mention does not occur you can expose the properties and manipulate them from the toolbox. 35 | [Browsable(false)] 36 | public bool IsMainMenu 37 | { 38 | get { return isMainMenu; } 39 | set { isMainMenu = value; } 40 | } 41 | 42 | [Browsable(false)] 43 | public int MenuItemHeight 44 | { 45 | get { return menuItemHeight; } 46 | set { menuItemHeight = value; } 47 | } 48 | 49 | [Browsable(false)] 50 | public Color MenuItemTextColor 51 | { 52 | get { return menuItemTextColor; } 53 | set { menuItemTextColor = value; } 54 | } 55 | 56 | [Browsable(false)] 57 | public Color PrimaryColor 58 | { 59 | get { return primaryColor; } 60 | set { primaryColor = value; } 61 | } 62 | 63 | //Private methods 64 | private void LoadMenuItemHeight() 65 | { 66 | if (isMainMenu) 67 | menuItemHeaderSize = new Bitmap(25, 45); 68 | else menuItemHeaderSize = new Bitmap(20, menuItemHeight); 69 | 70 | foreach (ToolStripMenuItem menuItemL1 in this.Items) 71 | { 72 | menuItemL1.ImageScaling = ToolStripItemImageScaling.None; 73 | if (menuItemL1.Image == null) menuItemL1.Image = menuItemHeaderSize; 74 | 75 | foreach (ToolStripMenuItem menuItemL2 in menuItemL1.DropDownItems) 76 | { 77 | menuItemL2.ImageScaling = ToolStripItemImageScaling.None; 78 | if (menuItemL2.Image == null) menuItemL2.Image = menuItemHeaderSize; 79 | 80 | foreach (ToolStripMenuItem menuItemL3 in menuItemL2.DropDownItems) 81 | { 82 | menuItemL3.ImageScaling = ToolStripItemImageScaling.None; 83 | if (menuItemL3.Image == null) menuItemL3.Image = menuItemHeaderSize; 84 | 85 | foreach (ToolStripMenuItem menuItemL4 in menuItemL3.DropDownItems) 86 | { 87 | menuItemL4.ImageScaling = ToolStripItemImageScaling.None; 88 | if (menuItemL4.Image == null) menuItemL4.Image = menuItemHeaderSize; 89 | ///Level 5++ 90 | } 91 | } 92 | } 93 | } 94 | } 95 | 96 | //Overrides 97 | protected override void OnHandleCreated(EventArgs e) 98 | { 99 | base.OnHandleCreated(e); 100 | if (this.DesignMode == false) 101 | { 102 | this.Renderer = new MenuRenderer(isMainMenu, primaryColor, menuItemTextColor); 103 | LoadMenuItemHeight(); 104 | } 105 | } 106 | } 107 | } 108 | --------------------------------------------------------------------------------