先上效果图:

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 = ;
Point p = new Point(e.X, e.Y);
foreach (var v in Items)
{
Rectangle rect = new Rectangle(_itemW * index, , _itemW, _itemH);
if (rect.Contains(p))
{
_titleIndex = index;
_itemIndex = ;
break;
}
if (_titleIndex == index)
{
int i = ;
foreach (var item in v.Value)
{
rect = new Rectangle(, i * (_itemH - ) + _itemH, _itemW, (_itemH - ));
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(, , ));
e.Graphics.FillRectangle(brush, new Rectangle(, , this.Width, _itemH));
e.Graphics.FillRectangle(brush, new Rectangle(, , _itemW, this.Height));
if (Items != null)
{
Point p = this.PointToClient(Control.MousePosition);
StringFormat sf = new StringFormat()
{
LineAlignment = StringAlignment.Center
};
int index = ;
foreach (var v in Items)
{
Rectangle rect = new Rectangle(_itemW * index, , _itemW, _itemH);
Brush b = index == _titleIndex ? Brushes.BlueViolet : rect.Contains(p) ? Brushes.Gold : Brushes.Black;
if (index == ) rect.Offset(, );
e.Graphics.DrawString(v.Key, this.Font, b, rect, sf);
if (index == _titleIndex)
{
int i = ;
foreach (var item in v.Value)
{
rect = new Rectangle(, i * (_itemH - ) + _itemH, _itemW, (_itemH - ));
b = i == _itemIndex ? Brushes.White : rect.Contains(p) ? Brushes.LightGray : brush;
e.Graphics.FillRectangle(b, rect);
rect.Offset(, );
e.Graphics.DrawString(item.Name, this.Font, Brushes.Black, rect, sf);
i++;
}
}
index++;
}
}
e.Graphics.DrawLine(Pens.Gray, new Point(, _itemH), new Point(this.Width, _itemH));
brush.Dispose();
} /// <summary>
/// 初始化
/// </summary>
private void Initialize()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
} private const int _itemH = ;
private const int _itemW = ;
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(, );
this.setterPanel.Name = "setterPanel";
this.setterPanel.Size = new System.Drawing.Size(, );
this.setterPanel.TabIndex = ;
//
// 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,否则会报错

如果需要技术交流的,可以关注微信公众号:梦琪动漫屋 

【C#】自定义容器控件,设置界面控件,支持设计器拖入控件的更多相关文章

  1. Qt编写控件属性设计器11-导入xml

    一.前言 上一篇文章负责把设计好的控件数据导出到了xml文件,本偏文章负责把导出的xml数据文件导入,然后在画布上自动生成对应的控件,Qt内置的xml数据解析功能,非常强大,都封装在QtXml组件中, ...

  2. Qt编写控件属性设计器3-拉伸控件

    一.前言 插件控件加载了,拖曳控件也实现了,接下来就是一个最难点了,跟QtDesigner或者其他开发环境一样,能够任意自由的拉伸控件大小,移动位置,为了这个功能,还特别编写了一个控件来实现这个功能, ...

  3. Qt编写控件属性设计器2-拖曳控件

    一.前言 上一篇文章把插件加载好了,并且把插件中的所有控件都显示到了列表框中,这次要做的就是实现拖曳控件的功能,用户选择一个控件拖曳到画布上,松开,在松开位置处自动实例化该控件,这个需要用到dropE ...

  4. Qt编写控件属性设计器

    一.前言 自从研究Qt编写自定义控件以来,一发不可收拾,越多越多人有类似的需求找我定制控件,陆陆续续写了上百个控件,目前已超过150个,于是逐渐衍生了另外一个需求,提供一个控件属性设计器,类似QtDe ...

  5. Qt编写的项目作品2-控件属性设计器(组态)

    一.功能特点 自动加载插件文件中的所有控件生成列表,默认自带的控件超过120个. 拖曳到画布自动生成对应的控件,所见即所得. 右侧中文属性栏,改变对应的属性立即应用到对应选中控件,直观简洁,非常适合小 ...

  6. Qt编写控件属性设计器4-加载属性

    一.前言 控件能加载拖曳拉伸了,这些都是基本的前提工作,接下来的重点就是要动态加载选中控件的属性了,Qt的属性机制那是异常的强大,只能用强大到爆来形容,Qt中编写自定义控件,如果属性都用Q_PROPE ...

  7. WinForm编程时窗体设计器中ComboBox控件大小的设置

    问题描述: 在VS中的窗体设计器中拖放一个ComboBox控件后想调整控件的大小.发现在控件上用鼠标只能拖动宽度(Width)无法拖动(Height). 解决过程: 1.控件无法拖动,就在属性窗口中设 ...

  8. Qt编写控件属性设计器12-用户属性

    一.前言 用户属性是后面新增加的一个功能,自定义控件如果采用的Q_PROPERTY修饰的属性,会自动识别到属性栏中,这个一般称为控件属性,在组态设计软件中,光有控件本身的控件属性还是不够的,毕竟这些属 ...

  9. Qt编写控件属性设计器10-导出xml

    一.前言 能够导出控件布局和属性设置数据到xml文件或者其他文件,也是一个非常实用的功能,类似于QtDesigner中把页面设计好以后生成的.ui结尾的文件,其实就是xml文件,按照约定的规则存储好控 ...

随机推荐

  1. Requests: 让 HTTP 服务人类

    requests 2.18.1文档 requests流式post文件 Calling SOAP Web service using requests module of

  2. Webbench是有名的网站压力测试工具

    [root@666 webbench-1.5]# yum install ctags [root@666 webbench-1.5]#make && make install inst ...

  3. (原创)一个和c#中Lazy<T>类似的c++ Lazy<T>类的实现

    在.net 4.0中增加一个延迟加载类Lazy<T>,它的作用是实现按需延迟加载,也许很多人用过.一个典型的应用场景是这样的:当初始化某个对象时,该对象引用了一个大对象,需要创建,这个对象 ...

  4. iOS开发之蓝牙

    // //  ViewController.m //  13-蓝牙 // //  Created by hongqiangli on 2017/7/21. //  Copyright © 李洪强. A ...

  5. 连接web端,mysql,返回乱码解决

    参考:http://yushan.iteye.com/blog/265019

  6. delphi中Webbrowser疑难问题集锦<转>

    1.获得网页中变量值      htm中<script> var currID=123</script>      程序中可以这么调用 id := Form1.WebBrows ...

  7. js获取上传图片真实的尺寸大小和存储大小

    https://blog.csdn.net/u014236259/article/details/52885591 ****************************************** ...

  8. 【Linux】linux下gzip的压缩/解压缩详解

    Linux压缩保留源文件的方法: gzip –c filename > filename.gz Linux解压缩保留源文件的方法: gunzip –c filename.gz > file ...

  9. JAVA-JSP内置对象之request范围

    相关资料:<21天学通Java Web开发> request范围1.在一次请求内有效.2.如果页面从一个页面跳转到另一个页面,那么属性就失效了.3.如果使用服务器端跳转<jsp:fo ...

  10. Node.js学习笔记(3)--url.parse方法

    说明(2017-5-2 14:23:47): 1. index.html <!DOCTYPE html> <html lang="en"> <head ...