winform快速开发平台 -> 工作流组件(仿GooFlow)

     对于web方向的工作流,一直在用gooflow对于目前我的winform开发平台却没有较好的工作流组件。

   针对目前的项目经验告诉我们。一个工作流控件是很必要的。 当然在winform方面的工作流第三方组件在网上找了很久,也没有发现自己比较心仪的组件。 

     对于工作流组件通过web方式来实现具有绝对的优势。我的这套winform平台当然也不能少了工作流组件。 

     通过winform来实现自己的工作流组件,目前我想到的指能通过GDI+重绘的方式来实现工作流的方案。

  说干就干,如下图这是我通过GDI+绘制的工作流控件: 

      图片

设计思想:

    控件中我们需要一些定义的节点:如开始、结束、自定义节点、画线,和一个内容画布组成

    通过抽象出线、点、以及item。进行重绘。

    画布进行双缓冲来解决绘制时导致的出线闪屏问题。 

简单介绍:

    画布中的网格绘制方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
var gridPen = new Pen(Color.Silver)
{
    DashStyle = DashStyle.Custom,
    DashPattern = new float[] { 2f, 2f }
};
 for (int column = 0; column < (int)Math.Ceiling((double)this.Width / (double)gridAverage); column++)
{
    bufferGraphics.DrawLine(gridPen, new Point(column * gridAverage, 0), new Point(column * gridAverage, this.Height));
}
 for (int row = 0; row < (int)Math.Ceiling((double)this.Height / (double)gridAverage); row++)
{
    bufferGraphics.DrawLine(gridPen, new Point(0, row * gridAverage), new Point(this.Width, row * gridAverage));
}

  绘制节点抽象类型代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public enum ItemType
{
    /// <summary>
    /// 开始
    /// </summary>
    Start,
    /// <summary>
    /// 工作流
    /// </summary>
    Custom,
    /// <summary>
    /// 线
    /// </summary>
    Line,
    /// <summary>
    /// 结束
    /// </summary>
    End
 }

绘制连线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
public void DrawLine(Graphics grp, Pen pen)
{
    if (m_startPoint == null || m_endPoint == null) return;
 
    var startX = m_startPoint.ItemLocate.X + m_startPoint.ItemImage.Width / 2;
    var startY = m_startPoint.ItemLocate.Y + m_startPoint.ItemImage.Height / 2;
 
    var endX = m_endPoint.ItemLocate.X + m_endPoint.ItemImage.Width / 2;
    var endY = m_endPoint.ItemLocate.Y + m_endPoint.ItemImage.Height / 2;
 
    #region 计算开始点位置
    if (m_startPoint.ItemLocate.X < m_endPoint.ItemLocate.X)
    {
        if (m_startPoint.ItemLocate.Y < m_endPoint.ItemLocate.Y - m_startPoint.ItemLocate.Y)
        {
            startX = m_startPoint.ItemLocate.X + m_startPoint.ItemImage.Width / 2;
            startY = m_startPoint.ItemLocate.Y + m_startPoint.ItemImage.Height;
        }
        else if (m_startPoint.ItemLocate.Y < m_endPoint.ItemLocate.Y + m_endPoint.ItemImage.Height)
        {
            startX = m_startPoint.ItemLocate.X + m_startPoint.ItemImage.Width;
            startY = m_startPoint.ItemLocate.Y + m_startPoint.ItemImage.Height / 2;
        }
        else
        {
            startX = m_startPoint.ItemLocate.X + m_startPoint.ItemImage.Width / 2;
            startY = m_startPoint.ItemLocate.Y;
        }
    }
    else
    {
        if (m_startPoint.ItemLocate.Y < m_endPoint.ItemLocate.Y - m_startPoint.ItemLocate.Y)
        {
            startX = m_startPoint.ItemLocate.X + m_startPoint.ItemImage.Width / 2;
            startY = m_startPoint.ItemLocate.Y + m_startPoint.ItemImage.Height;
        }
        else if (m_startPoint.ItemLocate.Y < m_endPoint.ItemLocate.Y + m_endPoint.ItemImage.Height)
        {
            startX = m_startPoint.ItemLocate.X;
            startY = m_startPoint.ItemLocate.Y + m_startPoint.ItemImage.Height / 2;
        }
        else
        {
            startX = m_startPoint.ItemLocate.X + m_startPoint.ItemImage.Width / 2;
            startY = m_startPoint.ItemLocate.Y;
        }
    }
    #endregion
 
    #region 计算结束点位置
 
    if (m_startPoint.ItemLocate.X < m_endPoint.ItemLocate.X)
    {
        if (m_startPoint.ItemLocate.Y < m_endPoint.ItemLocate.Y - m_startPoint.ItemLocate.Y)
        {
            endX = m_endPoint.ItemLocate.X + m_endPoint.ItemImage.Width / 2;
            endY = m_endPoint.ItemLocate.Y;
        }
        else if (m_startPoint.ItemLocate.Y < m_endPoint.ItemLocate.Y + m_endPoint.ItemImage.Height)
        {
            endX = m_endPoint.ItemLocate.X;
            endY = m_endPoint.ItemLocate.Y + m_endPoint.ItemImage.Height / 2;
        }
        else
        {
            endX = m_endPoint.ItemLocate.X + m_endPoint.ItemImage.Width / 2;
            endY = m_endPoint.ItemLocate.Y + m_endPoint.ItemImage.Height;
        }
    }
    else
    {
        if (m_startPoint.ItemLocate.Y < m_endPoint.ItemLocate.Y - m_startPoint.ItemLocate.Y)
        {
            endX = m_endPoint.ItemLocate.X + m_endPoint.ItemImage.Width / 2;
            endY = m_endPoint.ItemLocate.Y;
        }
        else if (m_startPoint.ItemLocate.Y < m_endPoint.ItemLocate.Y + m_endPoint.ItemImage.Height)
        {
            endX = m_endPoint.ItemLocate.X + m_endPoint.ItemImage.Width;
            endY = m_endPoint.ItemLocate.Y + m_endPoint.ItemImage.Height / 2;
        }
        else
        {
            endX = m_endPoint.ItemLocate.X + m_endPoint.ItemImage.Width / 2;
            endY = m_endPoint.ItemLocate.Y + m_endPoint.ItemImage.Height;
        }
    }
    #endregion
    var startPoint = new Point(startX, startY);
    var endPoint = new Point(endX, endY);
 
    grp.DrawLine(pen, startPoint, endPoint);
}

  

通过一点一滴的付出,每个时间点都会看到他的完善。同时也期待着的他的成长。

Winform快速开发平台系列:

官网连接

1.winform快速开发平台 -> 让有限的资源创造无限的价值!

2.winform快速开发平台 -> 基础组件之分页控件

3.winform快速开发平台 -> 绑定ComboBox数据控件

4.winform快速开发平台 -> 工作流组件(仿GooFlow)

5.winform快速开发平台 -> 通用权限管理之动态菜单

posted @   真有意思  阅读(8438)  评论(36编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示