官网

http://www.hzhcontrols.com

前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

GitHub:https://github.com/kwwwvagaa/NetWinformControl

码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492 

麻烦博客下方点个【推荐】,谢谢

NuGet

Install-Package HZH_Controls

目录

https://www.cnblogs.com/bfyx/p/11364884.html

用处及效果

准备工作

依然是用GDI+画的,不懂的可以先百度一下

开始

添加一个实体类,用以记录数据源节点信息

  public class MindMappingItemEntity
{
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>The identifier.</value>
public string ID { get; set; }
private string _text;
/// <summary>
/// Gets or sets the text.
/// </summary>
/// <value>The text.</value>
public string Text
{
get { return _text; }
set
{
_text = value;
ResetSize();
}
}
/// <summary>
/// Gets or sets the data source.
/// </summary>
/// <value>The data source.</value>
public object DataSource { get; set; }
/// <summary>
/// The childrens
/// </summary>
private MindMappingItemEntity[] _Childrens;
/// <summary>
/// Gets or sets the childrens.
/// </summary>
/// <value>The childrens.</value>
public MindMappingItemEntity[] Childrens
{
get { return _Childrens; }
set
{
_Childrens = value;
if (value != null && value.Length > )
{
value.ToList().ForEach(p => { if (p != null) { p.ParentItem = this; } });
}
}
}
/// <summary>
/// The back color
/// </summary>
private Color backColor = Color.Transparent; /// <summary>
/// Gets or sets the color of the back.
/// </summary>
/// <value>The color of the back.</value>
public Color BackColor
{
get { return backColor; }
set { backColor = value; }
} private Font font = new Font("微软雅黑", ); public Font Font
{
get { return font; }
set
{
font = value;
ResetSize();
}
} /// <summary>
/// The fore color
/// </summary>
private Color foreColor = Color.Black; /// <summary>
/// Gets or sets the color of the fore.
/// </summary>
/// <value>The color of the fore.</value>
public Color ForeColor
{
get { return foreColor; }
set { foreColor = value; }
}
private bool _IsExpansion = false;
/// <summary>
/// Gets or sets a value indicating whether the instance is expanded.
/// </summary>
/// <value><c>true</c> if this instance is expansion; otherwise, <c>false</c>.</value>
public bool IsExpansion
{
get
{
return _IsExpansion;
}
set
{
if (value == _IsExpansion)
return;
_IsExpansion = value;
if (!value)
{
_Childrens.ToList().ForEach(p => { if (p != null) { p.IsExpansion = false; } });
} }
} /// <summary>
/// Gets the parent item.
/// </summary>
/// <value>The parent item.</value>
public MindMappingItemEntity ParentItem { get; private set; }
/// <summary>
/// Gets all childrens maximum show count.
/// </summary>
/// <value>All childrens maximum show count.</value>
public int AllChildrensMaxShowHeight { get { return GetAllChildrensMaxShowHeight(); } }
/// <summary>
/// Gets the maximum level.
/// </summary>
/// <value>The maximum level.</value>
public int AllChildrensMaxShowWidth { get { return GetAllChildrensMaxShowWidth(); } } /// <summary>
/// Gets all childrens maximum show count.
/// </summary>
/// <returns>System.Int32.</returns>
private int GetAllChildrensMaxShowHeight()
{
if (!_IsExpansion || _Childrens == null || _Childrens.Length <= )
return ItemHeight + ;
else
{
return _Childrens.Sum(p => p == null ? : p.AllChildrensMaxShowHeight);
}
}
/// <summary>
/// Gets the maximum level.
/// </summary>
/// <returns>System.Int32.</returns>
private int GetAllChildrensMaxShowWidth()
{
if (!_IsExpansion || _Childrens == null || _Childrens.Length <= )
return ItemWidth + ;
else
{
return + _Childrens.Max(p => p == null ? : p.AllChildrensMaxShowWidth);
}
}
/// <summary>
/// Gets or sets the working rectangle.
/// </summary>
/// <value>The working rectangle.</value>
internal RectangleF WorkingRectangle { get; set; }
/// <summary>
/// Gets or sets the draw rectangle.
/// </summary>
/// <value>The draw rectangle.</value>
internal RectangleF DrawRectangle { get; set; }
/// <summary>
/// Gets or sets the expansion rectangle.
/// </summary>
/// <value>The expansion rectangle.</value>
internal RectangleF ExpansionRectangle { get; set; }
/// <summary>
/// Gets the height of the item.
/// </summary>
/// <value>The height of the item.</value>
private int ItemHeight { private get; private set; }
/// <summary>
/// Gets the width of the item.
/// </summary>
/// <value>The width of the item.</value>
private int ItemWidth { private get; private set; }
/// <summary>
/// Resets the size.
/// </summary>
private void ResetSize()
{
string _t = _text;
if (string.IsNullOrEmpty(_t))
{
_t = "aaaa";
}
Bitmap bit = new Bitmap(, );
var g = Graphics.FromImage(bit);
var size = g.MeasureString(_t, font);
g.Dispose();
bit.Dispose();
ItemHeight = (int)size.Height;
ItemWidth = (int)size.Width;
}
}

主要属性说明:

Text:显示文字

Childrens:子节点信息

BackColor:节点颜色

IsExpansion:是否展开子节点

ParentItem:父级节点

AllChildrensMaxShowHeight:该节点包含所有子节点需要显示的高度,通过私有函数GetAllChildrensMaxShowHeight()返回结果

AllChildrensMaxShowWidth:该节点包含所有子节点需要显示的宽度,通过私有函数GetAllChildrensMaxShowWidth()返回结果

WorkingRectangle:该节点以及所有子节点的工作区域

DrawRectangle:该节点的绘制区域

ExpansionRectangle:展开折叠按钮的绘制区域

ItemHeight:该节点的高度

ItemWidth:该节点的宽度

主要函数说明:

GetAllChildrensMaxShowHeight:获取当前节点及所有子节点需要的最大高度

GetAllChildrensMaxShowWidth:获取当前节点及所有子节点需要的最大宽度

ResetSize:当文本和字体改变时重新计算宽高

添加一个类UCMindMapping,继承UserControl

添加一些属性

  /// <summary>
/// The line color
/// </summary>
private Color lineColor = Color.Black; /// <summary>
/// Gets or sets the color of the line.
/// </summary>
/// <value>The color of the line.</value>
[Description("线条颜色"), Category("自定义")]
public Color LineColor
{
get { return lineColor; }
set
{
lineColor = value;
Refresh();
}
}
/// <summary>
/// The split width
/// </summary>
private int splitWidth = ;
// private int itemHeight = 20;
/// <summary>
/// The padding
/// </summary>
private int padding = ; /// <summary>
/// The m rect working
/// </summary>
Rectangle m_rectWorking = Rectangle.Empty;
/// <summary>
/// Occurs when [item clicked].
/// </summary>
public event EventHandler ItemClicked;
/// <summary>
/// The data source
/// </summary>
private MindMappingItemEntity dataSource;
/// <summary>
/// Gets or sets the data source.
/// </summary>
/// <value>The data source.</value>
[Description("数据源"), Category("自定义")]
public MindMappingItemEntity DataSource
{
get { return dataSource; }
set
{
dataSource = value; ResetSize();
}
}

一个辅助函数,用以在大小过数据改变时计算工作区域和位置

  /// <summary>
/// 重置大小
/// </summary>
private void ResetSize()
{
if (this.Parent == null)
return;
try
{
ControlHelper.FreezeControl(this, true);
if (dataSource == null)
{
m_rectWorking = Rectangle.Empty;
this.Size = this.Parent.Size;
}
else
{
int intWidth = dataSource.AllChildrensMaxShowWidth;
int intHeight = dataSource.AllChildrensMaxShowHeight;
this.Width = intWidth + padding * ;
this.Height = intHeight + padding * ;
if (this.Width < this.Parent.Width)
this.Width = this.Parent.Width;
m_rectWorking = new Rectangle(padding, padding, intWidth, intHeight);
if (this.Height > this.Parent.Height)
{
//this.Location = new Point(0, 0);
}
else
this.Location = new Point(, (this.Parent.Height - this.Height) / );
}
}
finally
{
ControlHelper.FreezeControl(this, false);
}
}

重绘

  /// <summary>
/// 引发 <see cref="E:System.Windows.Forms.Control.Paint" /> 事件。
/// </summary>
/// <param name="e">包含事件数据的 <see cref="T:System.Windows.Forms.PaintEventArgs" />。</param>
protected override void OnPaint(PaintEventArgs e)
{
try
{
base.OnPaint(e);
if (m_rectWorking == Rectangle.Empty || m_rectWorking == null)
return;
var g = e.Graphics;
g.SetGDIHigh(); int intHeight = dataSource.AllChildrensMaxShowHeight;
dataSource.WorkingRectangle = new RectangleF(m_rectWorking.Left, m_rectWorking.Top + (m_rectWorking.Height - intHeight) / , m_rectWorking.Width, intHeight); DrawItem(dataSource, g);
}
catch (Exception exc)
{
MessageBox.Show(exc.ToString(), "错误");
}
}
 /// <summary>
/// 画节点
/// </summary>
/// <param name="item">The item.</param>
/// <param name="g">The g.</param>
private void DrawItem(MindMappingItemEntity item, Graphics g)
{
//节点
var size = g.MeasureString(item.Text, item.Font);
item.DrawRectangle = new RectangleF(item.WorkingRectangle.Left + , item.WorkingRectangle.Top + (item.WorkingRectangle.Height - size.Height) / + , size.Width + , size.Height + );
GraphicsPath drawPath = item.DrawRectangle.CreateRoundedRectanglePath();
g.FillPath(new SolidBrush(item.BackColor), drawPath);
g.DrawString(item.Text, item.Font, new SolidBrush(item.ForeColor), item.DrawRectangle.Location.X + , item.DrawRectangle.Location.Y + );
//子节点
if (item.Childrens != null && item.IsExpansion)
{
for (int i = ; i < item.Childrens.Length; i++)
{
var child = item.Childrens[i];
if (i == )
{
child.WorkingRectangle = new RectangleF(item.DrawRectangle.Right + splitWidth, item.WorkingRectangle.Top, item.WorkingRectangle.Width - (item.DrawRectangle.Width + splitWidth), child.AllChildrensMaxShowHeight);
}
else
{
child.WorkingRectangle = new RectangleF(item.DrawRectangle.Right + splitWidth, item.Childrens[i - ].WorkingRectangle.Bottom, item.WorkingRectangle.Width - (item.DrawRectangle.Width + splitWidth), child.AllChildrensMaxShowHeight);
}
DrawItem(child, g);
}
}
//连线
if (item.ParentItem != null)
{
g.DrawLines(new Pen(new SolidBrush(lineColor), ), new PointF[]
{
new PointF(item.ParentItem.DrawRectangle.Right,item.ParentItem.DrawRectangle.Top+item.ParentItem.DrawRectangle.Height/),
new PointF(item.ParentItem.DrawRectangle.Right+,item.ParentItem.DrawRectangle.Top+item.ParentItem.DrawRectangle.Height/),
//new PointF(item.ParentItem.DrawRectangle.Right+12,item.DrawRectangle.Top+item.DrawRectangle.Height/2),
new PointF(item.DrawRectangle.Left-,item.DrawRectangle.Top+item.DrawRectangle.Height/),
new PointF(item.DrawRectangle.Left,item.DrawRectangle.Top+item.DrawRectangle.Height/),
});
}
//展开折叠按钮
if (item.Childrens != null && item.Childrens.Length > )
{
RectangleF _rect = new RectangleF(item.DrawRectangle.Right + , item.DrawRectangle.Top + (item.DrawRectangle.Height - ) / , , );
item.ExpansionRectangle = _rect;
g.FillEllipse(new SolidBrush(this.BackColor), _rect);
g.DrawEllipse(new Pen(new SolidBrush(Color.Black)), _rect);
g.DrawLine(new Pen(new SolidBrush(lineColor)), _rect.Left + , _rect.Y + _rect.Height / , _rect.Right - , _rect.Y + _rect.Height / );
if (!item.IsExpansion)
{
g.DrawLine(new Pen(new SolidBrush(lineColor)), _rect.Left + _rect.Width / , _rect.Top + , _rect.Left + _rect.Width / , _rect.Bottom - );
}
}
}

控件的单击和双击时间来处理展开折叠事件

  /// <summary>
/// 双击处理,主要用于检测节点双击展开折叠
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
void UCMindMapping_DoubleClick(object sender, EventArgs e)
{
var mouseLocation = this.PointToClient(Control.MousePosition); bool bln = CheckExpansionDoubleClick(dataSource, mouseLocation);
if (bln)
{
ResetSize();
this.Parent.Refresh();
}
} /// <summary>
/// 单击处理,主要用于单击节点事件和,展开关闭圆圈处理
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
void UCMindMapping_Click(object sender, EventArgs e)
{
var mouseLocation = this.PointToClient(Control.MousePosition); bool bln = CheckExpansionClick(dataSource, mouseLocation);
if (bln)
{
ResetSize();
this.Parent.Refresh();
}
}
   /// <summary>
/// 双击检查
/// </summary>
/// <param name="item">The item.</param>
/// <param name="mouseLocation">The mouse location.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
private bool CheckExpansionDoubleClick(MindMappingItemEntity item, Point mouseLocation)
{
if (item == null)
return false;
else
{
if (item.DrawRectangle.Contains(mouseLocation))
{
item.IsExpansion = !item.IsExpansion;
return true;
}
if (item.Childrens != null && item.Childrens.Length > )
{
foreach (var child in item.Childrens)
{
var bln = CheckExpansionDoubleClick(child, mouseLocation);
if (bln)
return bln;
}
}
}
return false;
} /// <summary>
/// 单击检查
/// </summary>
/// <param name="item">The item.</param>
/// <param name="mouseLocation">The mouse location.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
private bool CheckExpansionClick(MindMappingItemEntity item, Point mouseLocation)
{
if (item == null)
return false;
else
{
if (ItemClicked != null && item.WorkingRectangle.Contains(mouseLocation))
{
ItemClicked(item, null);
}
else if (item.ExpansionRectangle.Contains(mouseLocation))
{
item.IsExpansion = !item.IsExpansion;
return true;
}
if (item.Childrens != null && item.Childrens.Length > )
{
foreach (var child in item.Childrens)
{
var bln = CheckExpansionClick(child, mouseLocation);
if (bln)
return bln;
}
}
}
return false;
}

完整代码

 // ***********************************************************************
// Assembly : HZH_Controls
// Created : 2019-09-11
//
// ***********************************************************************
// <copyright file="UCMindMapping.cs">
// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com
// </copyright>
//
// Blog: https://www.cnblogs.com/bfyx
// GitHub:https://github.com/kwwwvagaa/NetWinformControl
// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
//
// If you use this code, please keep this note.
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel; namespace HZH_Controls.Controls
{
/// <summary>
/// Class UCMindMapping.
/// Implements the <see cref="System.Windows.Forms.UserControl" />
/// </summary>
/// <seealso cref="System.Windows.Forms.UserControl" />
internal class UCMindMapping : UserControl
{
/// <summary>
/// The line color
/// </summary>
private Color lineColor = Color.Black; /// <summary>
/// Gets or sets the color of the line.
/// </summary>
/// <value>The color of the line.</value>
[Description("线条颜色"), Category("自定义")]
public Color LineColor
{
get { return lineColor; }
set
{
lineColor = value;
Refresh();
}
}
/// <summary>
/// The split width
/// </summary>
private int splitWidth = ;
// private int itemHeight = 20;
/// <summary>
/// The padding
/// </summary>
private int padding = ; /// <summary>
/// The m rect working
/// </summary>
Rectangle m_rectWorking = Rectangle.Empty;
/// <summary>
/// Occurs when [item clicked].
/// </summary>
public event EventHandler ItemClicked;
/// <summary>
/// The data source
/// </summary>
private MindMappingItemEntity dataSource;
/// <summary>
/// Gets or sets the data source.
/// </summary>
/// <value>The data source.</value>
[Description("数据源"), Category("自定义")]
public MindMappingItemEntity DataSource
{
get { return dataSource; }
set
{
dataSource = value; ResetSize();
}
}
/// <summary>
/// Initializes a new instance of the <see cref="UCMindMapping"/> class.
/// </summary>
public UCMindMapping()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.Selectable, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.Click += UCMindMapping_Click;
this.DoubleClick += UCMindMapping_DoubleClick;
this.Load += UCMindMapping_Load;
} /// <summary>
/// Handles the Load event of the UCMindMapping control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
void UCMindMapping_Load(object sender, EventArgs e)
{
if (this.Parent != null)
{
//父控件大小改变时重置大小和位置
this.Parent.SizeChanged += (a, b) =>
{
ResetSize();
};
}
} /// <summary>
/// 双击处理,主要用于检测节点双击展开折叠
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
void UCMindMapping_DoubleClick(object sender, EventArgs e)
{
var mouseLocation = this.PointToClient(Control.MousePosition); bool bln = CheckExpansionDoubleClick(dataSource, mouseLocation);
if (bln)
{
ResetSize();
this.Parent.Refresh();
}
} /// <summary>
/// 单击处理,主要用于单击节点事件和,展开关闭圆圈处理
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
void UCMindMapping_Click(object sender, EventArgs e)
{
var mouseLocation = this.PointToClient(Control.MousePosition); bool bln = CheckExpansionClick(dataSource, mouseLocation);
if (bln)
{
ResetSize();
this.Parent.Refresh();
}
} /// <summary>
/// 双击检查
/// </summary>
/// <param name="item">The item.</param>
/// <param name="mouseLocation">The mouse location.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
private bool CheckExpansionDoubleClick(MindMappingItemEntity item, Point mouseLocation)
{
if (item == null)
return false;
else
{
if (item.DrawRectangle.Contains(mouseLocation))
{
item.IsExpansion = !item.IsExpansion;
return true;
}
if (item.Childrens != null && item.Childrens.Length > )
{
foreach (var child in item.Childrens)
{
var bln = CheckExpansionDoubleClick(child, mouseLocation);
if (bln)
return bln;
}
}
}
return false;
} /// <summary>
/// 单击检查
/// </summary>
/// <param name="item">The item.</param>
/// <param name="mouseLocation">The mouse location.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
private bool CheckExpansionClick(MindMappingItemEntity item, Point mouseLocation)
{
if (item == null)
return false;
else
{
if (ItemClicked != null && item.WorkingRectangle.Contains(mouseLocation))
{
ItemClicked(item, null);
}
else if (item.ExpansionRectangle.Contains(mouseLocation))
{
item.IsExpansion = !item.IsExpansion;
return true;
}
if (item.Childrens != null && item.Childrens.Length > )
{
foreach (var child in item.Childrens)
{
var bln = CheckExpansionClick(child, mouseLocation);
if (bln)
return bln;
}
}
}
return false;
} /// <summary>
/// 引发 <see cref="E:System.Windows.Forms.Control.Paint" /> 事件。
/// </summary>
/// <param name="e">包含事件数据的 <see cref="T:System.Windows.Forms.PaintEventArgs" />。</param>
protected override void OnPaint(PaintEventArgs e)
{
try
{
base.OnPaint(e);
if (m_rectWorking == Rectangle.Empty || m_rectWorking == null)
return;
var g = e.Graphics;
g.SetGDIHigh(); int intHeight = dataSource.AllChildrensMaxShowHeight;
dataSource.WorkingRectangle = new RectangleF(m_rectWorking.Left, m_rectWorking.Top + (m_rectWorking.Height - intHeight) / , m_rectWorking.Width, intHeight); DrawItem(dataSource, g);
}
catch (Exception exc)
{
MessageBox.Show(exc.ToString(), "错误");
}
} /// <summary>
/// 画节点
/// </summary>
/// <param name="item">The item.</param>
/// <param name="g">The g.</param>
private void DrawItem(MindMappingItemEntity item, Graphics g)
{
//节点
var size = g.MeasureString(item.Text, item.Font);
item.DrawRectangle = new RectangleF(item.WorkingRectangle.Left + , item.WorkingRectangle.Top + (item.WorkingRectangle.Height - size.Height) / + , size.Width + , size.Height + );
GraphicsPath drawPath = item.DrawRectangle.CreateRoundedRectanglePath();
g.FillPath(new SolidBrush(item.BackColor), drawPath);
g.DrawString(item.Text, item.Font, new SolidBrush(item.ForeColor), item.DrawRectangle.Location.X + , item.DrawRectangle.Location.Y + );
//子节点
if (item.Childrens != null && item.IsExpansion)
{
for (int i = ; i < item.Childrens.Length; i++)
{
var child = item.Childrens[i];
if (i == )
{
child.WorkingRectangle = new RectangleF(item.DrawRectangle.Right + splitWidth, item.WorkingRectangle.Top, item.WorkingRectangle.Width - (item.DrawRectangle.Width + splitWidth), child.AllChildrensMaxShowHeight);
}
else
{
child.WorkingRectangle = new RectangleF(item.DrawRectangle.Right + splitWidth, item.Childrens[i - ].WorkingRectangle.Bottom, item.WorkingRectangle.Width - (item.DrawRectangle.Width + splitWidth), child.AllChildrensMaxShowHeight);
}
DrawItem(child, g);
}
}
//连线
if (item.ParentItem != null)
{
g.DrawLines(new Pen(new SolidBrush(lineColor), ), new PointF[]
{
new PointF(item.ParentItem.DrawRectangle.Right,item.ParentItem.DrawRectangle.Top+item.ParentItem.DrawRectangle.Height/),
new PointF(item.ParentItem.DrawRectangle.Right+,item.ParentItem.DrawRectangle.Top+item.ParentItem.DrawRectangle.Height/),
//new PointF(item.ParentItem.DrawRectangle.Right+12,item.DrawRectangle.Top+item.DrawRectangle.Height/2),
new PointF(item.DrawRectangle.Left-,item.DrawRectangle.Top+item.DrawRectangle.Height/),
new PointF(item.DrawRectangle.Left,item.DrawRectangle.Top+item.DrawRectangle.Height/),
});
}
//展开折叠按钮
if (item.Childrens != null && item.Childrens.Length > )
{
RectangleF _rect = new RectangleF(item.DrawRectangle.Right + , item.DrawRectangle.Top + (item.DrawRectangle.Height - ) / , , );
item.ExpansionRectangle = _rect;
g.FillEllipse(new SolidBrush(this.BackColor), _rect);
g.DrawEllipse(new Pen(new SolidBrush(Color.Black)), _rect);
g.DrawLine(new Pen(new SolidBrush(lineColor)), _rect.Left + , _rect.Y + _rect.Height / , _rect.Right - , _rect.Y + _rect.Height / );
if (!item.IsExpansion)
{
g.DrawLine(new Pen(new SolidBrush(lineColor)), _rect.Left + _rect.Width / , _rect.Top + , _rect.Left + _rect.Width / , _rect.Bottom - );
}
}
} /// <summary>
/// 重置大小
/// </summary>
private void ResetSize()
{
if (this.Parent == null)
return;
try
{
ControlHelper.FreezeControl(this, true);
if (dataSource == null)
{
m_rectWorking = Rectangle.Empty;
this.Size = this.Parent.Size;
}
else
{
int intWidth = dataSource.AllChildrensMaxShowWidth;
int intHeight = dataSource.AllChildrensMaxShowHeight;
this.Width = intWidth + padding * ;
this.Height = intHeight + padding * ;
if (this.Width < this.Parent.Width)
this.Width = this.Parent.Width;
m_rectWorking = new Rectangle(padding, padding, intWidth, intHeight);
if (this.Height > this.Parent.Height)
{
//this.Location = new Point(0, 0);
}
else
this.Location = new Point(, (this.Parent.Height - this.Height) / );
}
}
finally
{
ControlHelper.FreezeControl(this, false);
}
}
}
}

最后再添加一个父控件,来包裹该控件,用以可以有滚动条的处理

添加一个用户控件UCMindMappingPanel,控件上添加一个上面新增的ucMindMapping,

完整代码

 // ***********************************************************************
// Assembly : HZH_Controls
// Created : 2019-09-11
//
// ***********************************************************************
// <copyright file="UCMindMappingPanel.cs">
// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com
// </copyright>
//
// Blog: https://www.cnblogs.com/bfyx
// GitHub:https://github.com/kwwwvagaa/NetWinformControl
// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
//
// If you use this code, please keep this note.
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms; namespace HZH_Controls.Controls
{
/// <summary>
/// Class UCMindMappingPanel.
/// Implements the <see cref="System.Windows.Forms.UserControl" />
/// </summary>
/// <seealso cref="System.Windows.Forms.UserControl" />
public partial class UCMindMappingPanel : UserControl
{
/// <summary>
/// The data source
/// </summary>
private MindMappingItemEntity dataSource; /// <summary>
/// Gets or sets the data source.
/// </summary>
/// <value>The data source.</value>
[Description("数据源"), Category("自定义")]
public MindMappingItemEntity DataSource
{
get { return dataSource; }
set
{
dataSource = value;
this.ucMindMapping1.DataSource = value;
}
}
/// <summary>
/// Gets or sets the data source.
/// </summary>
/// <value>The data source.</value>
[Description("数据源"), Category("自定义")]
public event EventHandler ItemClicked; /// <summary>
/// The line color
/// </summary>
private Color lineColor = Color.Black; /// <summary>
/// Gets or sets the color of the line.
/// </summary>
/// <value>The color of the line.</value>
[Description("线条颜色"), Category("自定义")]
public Color LineColor
{
get { return lineColor; }
set
{
lineColor = value;
this.ucMindMapping1.LineColor = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="UCMindMappingPanel"/> class.
/// </summary>
public UCMindMappingPanel()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.Selectable, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(ControlStyles.UserPaint, true);
InitializeComponent();
ucMindMapping1.ItemClicked += ucMindMapping1_ItemClicked;
} void ucMindMapping1_ItemClicked(object sender, EventArgs e)
{
if (ItemClicked != null)
{
ItemClicked(sender, e);
}
}
}
}
 namespace HZH_Controls.Controls
{
partial class UCMindMappingPanel
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null; /// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
} #region 组件设计器生成的代码 /// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.ucMindMapping1 = new HZH_Controls.Controls.UCMindMapping();
this.SuspendLayout();
//
// ucMindMapping1
//
this.ucMindMapping1.Location = new System.Drawing.Point(, );
this.ucMindMapping1.Name = "ucMindMapping1";
this.ucMindMapping1.Size = new System.Drawing.Size(, );
this.ucMindMapping1.TabIndex = ;
//
// UCMindMappingPanel
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.AutoScroll = true;
this.BackColor = System.Drawing.Color.White;
this.Controls.Add(this.ucMindMapping1);
this.Name = "UCMindMappingPanel";
this.Size = new System.Drawing.Size(, );
this.ResumeLayout(false); } #endregion private UCMindMapping ucMindMapping1;
}
}

最后的话

如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星星吧

(六十五)c#Winform自定义控件-思维导图/组织架构图(工业)的更多相关文章

  1. (六十)c#Winform自定义控件-鼓风机(工业)

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

  2. 第三百六十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的基本查询

    第三百六十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的基本查询 1.elasticsearch(搜索引擎)的查询 elasticsearch是功能 ...

  3. Gradle 1.12用户指南翻译——第六十五章. Maven 发布(新)

    其他章节的翻译请参见:http://blog.csdn.net/column/details/gradle-translation.html翻译项目请关注Github上的地址:https://gith ...

  4. “全栈2019”Java第六十五章:接口与默认方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. 孤荷凌寒自学python第六十五天学习mongoDB的基本操作并进行简单封装4

    孤荷凌寒自学python第六十五天学习mongoDB的基本操作并进行简单封装4 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第十一天. 今天继续学习mongoDB的简单操作 ...

  6. OpenCV开发笔记(六十五):红胖子8分钟带你深入了解ORB特征点(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  7. 《手把手教你》系列技巧篇(六十五)-java+ selenium自动化测试 - cookie -下篇(详细教程)

    1.简介 今天这一篇,宏哥主要讲解:利用WebDriver 提供可以读取.添加和删除cookie 信息的相关操作方法.验证浏览器中是否存在某个cookie.原因是:因为基于真实的cookie 的测试是 ...

  8. 公司人员组织架构图用思维导图软件MindManager怎么做

    有朋友一直不太明白组织架构图怎么做,其实组织架构图就是组织结构图.小编今天就在这里以一个公司为例,来给大家演示一番人员组织结构图怎么做. 老规矩,先说一下小编使用的软件跟电脑系统,这里用的是MindM ...

  9. (五十)c#Winform自定义控件-滑块

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

随机推荐

  1. ethtool工具使用实例

    使用ethtool工具可以查看和修改网卡(NIC卡)设备配置,下面我们来看ethtool的具体用法. 1.显示网卡属性 ethtool命令后直接跟网卡名称,可以显示关于该网卡的属性值: # ethto ...

  2. ArcGIS数据格式详解

  3. 洛谷 P2044 [NOI2012]随机数生成器

    题意简述 读入X[0], m, a, c, n和g $ X[n+1]=(a*X[n]+c)\mod m $ 求X数列的第n项对g取余的值. 题解思路 矩阵加速 设\[ F=\begin{bmatrix ...

  4. vs 中本地 git 的基本使用

    用 svn  有个毛病就是只有在改好了之后,才能提交.当周期比较长的时候,连自己都不知道自己改了什么东西,或者意外断电的时候,vs 中已保持的项目都有可能被 vs 去掉. 这个时候,使用 git 创建 ...

  5. MQTT的学习之Mosquitto安装和使用

    Mosquitto是一个实现了MQTT3.1协议的代理服务器,由MQTT协议创始人之一的Andy Stanford-Clark开发,它为我们提供了非常棒的轻量级数据交换的解决方案.本文的主旨在于记录M ...

  6. net core Webapi基础工程搭建(六)——数据库操作_Part 1

    目录 前言 SqlSugar Service层 BaseService(基类) 小结 前言 后端开发最常打交道的就是数据库了(静态网站靠边),上一篇net core Webapi基础工程搭建(五)-- ...

  7. mysql datetime timestamp区别

    timestamp 支持数据库级UTC 时区 datetime 不支持  timestamp占4个字节 datetime占8个字节 timestamp所能存储的时间范围为:'1970-01-01 00 ...

  8. slice splice(数组) 和 slice substr substring split (字符串)的区别

    array.slice(start,end)slice()如果不传入参数二,那么将从参数一的索引位置开始截取,一直到数组尾如果两个参数中的任何一个是负数,array.length会和它们相加 stri ...

  9. Scala 系列(十)—— 函数 & 闭包 & 柯里化

    一.函数 1.1 函数与方法 Scala 中函数与方法的区别非常小,如果函数作为某个对象的成员,这样的函数被称为方法,否则就是一个正常的函数. // 定义方法 def multi1(x:Int) = ...

  10. C#开发BIMFACE系列6 服务端API之获取文件信息

    在<C#开发BIMFACE系列4 服务端API之源上传文件>.<C#开发BIMFACE系列5 服务端API之文件直传>两篇文章中详细介绍了如何将本地文件上传到BIMFACE服务 ...