先上效果图:
1、先重写设置界面的控件功能:
public partial class SetterControl : UserControl { public SetterControl() { InitializeComponent(); Initialize(); } /// <summary> /// 获取或设置组列表 /// </summary> public Dictionary<string, List<SetterStrip>> Items; /// <summary> /// 容器 /// </summary> public Panel ItemContainer { get; set; } ///// <summary> ///// 加载 ///// </summary> ///// <param name="e"></param> //protected override void OnLoad(EventArgs e) //{ // base.OnLoad(e); //} /// <summary> /// 鼠标按下 /// </summary> /// <param name="e"></param> protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); this.Invalidate(); } /// <summary> /// 鼠标移动 /// </summary> /// <param name="e"></param> protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); this.Invalidate(); } /// <summary> /// 鼠标弹起 /// </summary> /// <param name="e"></param> protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); if (Items == null) return; int index = 0; Point p = new Point(e.X, e.Y); foreach (var v in Items) { Rectangle rect = new Rectangle(_itemW * index, 0, _itemW, _itemH); if (rect.Contains(p)) { _titleIndex = index; _itemIndex = 0; break; } if (_titleIndex == index) { int i = 0; foreach (var item in v.Value) { rect = new Rectangle(0, i * (_itemH - 10) + _itemH, _itemW, (_itemH - 10)); if (rect.Contains(p)) { _itemIndex = i; if (ItemContainer != null && item.LocationControl != null) ItemContainer.ScrollControlIntoView(item.LocationControl); break; } i++; } } index++; } this.Invalidate(); } /// <summary> /// 绘制 /// </summary> /// <param name="e"></param> protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Brush brush = new SolidBrush(Color.FromArgb(238, 238, 238)); e.Graphics.FillRectangle(brush, new Rectangle(0, 0, this.Width, _itemH)); e.Graphics.FillRectangle(brush, new Rectangle(0, 0, _itemW, this.Height)); if (Items != null) { Point p = this.PointToClient(Control.MousePosition); StringFormat sf = new StringFormat() { LineAlignment = StringAlignment.Center }; int index = 0; foreach (var v in Items) { Rectangle rect = new Rectangle(_itemW * index, 0, _itemW, _itemH); Brush b = index == _titleIndex ? Brushes.BlueViolet : rect.Contains(p) ? Brushes.Gold : Brushes.Black; if (index == 0) rect.Offset(20, 0); e.Graphics.DrawString(v.Key, this.Font, b, rect, sf); if (index == _titleIndex) { int i = 0; foreach (var item in v.Value) { rect = new Rectangle(0, i * (_itemH - 10) + _itemH, _itemW, (_itemH - 10)); b = i == _itemIndex ? Brushes.White : rect.Contains(p) ? Brushes.LightGray : brush; e.Graphics.FillRectangle(b, rect); rect.Offset(20, 0); e.Graphics.DrawString(item.Name, this.Font, Brushes.Black, rect, sf); i++; } } index++; } } e.Graphics.DrawLine(Pens.Gray, new Point(0, _itemH), new Point(this.Width, _itemH)); brush.Dispose(); } /// <summary> /// 初始化 /// </summary> private void Initialize() { this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); } private const int _itemH = 50; private const int _itemW = 130; private int _titleIndex; private int _itemIndex; } [Serializable] public class SetterStrip { /// <summary> /// 组名 /// </summary> public string Name { get; set; } /// <summary> /// 组控件坐标 /// </summary> public Control LocationControl { get; set; } }
2、实现设计器上直接拖入控件功能
[Designer(typeof(LDesigner))] [DesignTimeVisible(true)] public class MenuControlEx : SetterControl { public MenuControlEx() { InitializeComponent(); } /// <summary> /// 获取存放控件的Panel /// </summary> [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public Panel MenuPanel { get { return setterPanel; } } private void InitializeComponent() { this.setterPanel = new System.Windows.Forms.Panel(); this.SuspendLayout(); // // setterPanel // this.setterPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.setterPanel.AutoScroll = true; this.setterPanel.Location = new System.Drawing.Point(131, 52); this.setterPanel.Name = "setterPanel"; this.setterPanel.Size = new System.Drawing.Size(475, 499); this.setterPanel.TabIndex = 0; // // MenuControlEx // this.Controls.Add(this.setterPanel); this.ItemContainer = this.setterPanel; this.Name = "MenuControlEx"; this.ResumeLayout(false); } private System.Windows.Forms.Panel setterPanel; } public class LDesigner : ParentControlDesigner { private MenuControlEx _control; public override void Initialize(IComponent component) { base.Initialize(component); _control = (MenuControlEx)component; bool succ = this.EnableDesignMode(_control.MenuPanel, "setterPanel"); if (!succ) throw new Exception("加载控件失败"); } }
3、使用方法:
Dictionary<string, List<DLL.Controls.SetterStrip>> items = new Dictionary<string, List<DLL.Controls.SetterStrip>>(); items.Add("基础设置", new List<DLL.Controls.SetterStrip>() { new DLL.Controls.SetterStrip() {Name="常规", LocationControl=button1 }, new DLL.Controls.SetterStrip() { Name = "快捷键", LocationControl = button2 }, new DLL.Controls.SetterStrip() { Name = "显示", LocationControl = button3 } }); items.Add("安全设置", new List<DLL.Controls.SetterStrip>() { new DLL.Controls.SetterStrip() { Name = "安全1", LocationControl = button1 }, new DLL.Controls.SetterStrip() { Name = "安全2", LocationControl = button2 }, new DLL.Controls.SetterStrip() { Name = "安全3", LocationControl = button3 } }); menuControlEx1.Items = items;
//Name是显示的,LocationControl是用来点击按钮,控制滚动条定位的
2018/7/15 补上测试工程
PS. 如果是DLL方式使用,引用该DLL的地方也要引用 System.Design,否则会报错
如果需要技术交流的,可以关注微信公众号:梦琪动漫屋