C#高级GDI+实战:从零开发一个流程图》第07章:来吧,自定义“画布”控
三、创建类库及自定义控件
就像上节我们将抽象出来的形状和连线类都放到独立的类库中一样,我们同样将画布控件放到一个单独的类库中:

然后我们添加一个“自定义控件”,注意不是“用户控件”:

我们给画布起个名称:FCCanvas,就是FlowChartCanvas的简写。
这里为了方便编写教程,我们在后面增加V1、V2,用来区分。
创建好的结构如下:

四、移植代码到自定义控件
现在有了单独的画布控件,我们就将之前在程序中实现代码移植过来,我们在FCCanvasV1上右键->查看代码,进入后台代码。
1,双缓冲
首要的,我们在构造函数中添加开启双缓冲的代码:

2,重写OnPaint
有过自定义控件的读者会知道,自定义控件就相当于一个“画布”,控制所展示的内容全是我们用代码“画”上去的,而绘制的方法就是在OnPaint方法中。
我们将之前代码里的DrawAll方法里的代码复制进来:

因为已经在OnPaint方法中,所以不再需要传入Graphics对象,直接使用e.Graphics即可,此即当前控件的对象。
2,重写鼠标相关事件
我们之前是在panel控件上操作,现在我们是在整个控件上操作,所以我们需要重写下相关事件,这些可重写的方法一般都是以On开头,如:OnMouseDown等。
2.1,OnMouseDown
我们将之前代码中的MouseDown中的代码拷贝进来:

这里的变化有三点:
一是提示文本我们这里改为了触发事件的方式,我们定义了一个事件,通知订阅者使用,至于是否显示提示内容及如何显示提示内容我们控件不作管理。


二是添加连线时,连线的颜色不再是随机生成,也是触发一个事件,由调用方决定连线的颜色是什么:


为了防止调用方不订阅此事件,我们会默认连线颜色为黑色。
三是发起重新绘制的方式不一样了,之前是直接调用绘制所有方法DrawAll:

而现在我们也没有了DrawAll方法,DrawAll的实现被我们移植到了OnPaint方法中。所以我们直接调用控件自带的无效方法Invalidate(),来使窗口重绘:

内部逻辑简单而言就是:当我们调用Invalidate()后,系统会自动调用OnPaint方法,进而重绘。而这也是自定义控件的基础逻辑。
2.2,OnMouseMove
同样的,我们将之前代码中的MouseMove中的代码拷贝进来:

可以看到几乎一样,也是最后一步改为调用无效方法Invalidate(),来使窗口重绘。
2.3,OnMouseUp
同理:

3,形状集合、连线集合等定义
我们现在基本的实现都有了,那么就把之前的一些私有变量拿过来,像形状集合、连线集合、连线状态等:

4,公共方法
现在整个FCCanvasV1内部已经自洽了,但是有个问题:如何与外部交互?如何添加形状?
我们现在就来开放一些公共方法,来实现与外部的交互。
4.1,添加形状方法
最核心的也是最基本的功能,就是添加形状的方法:

我们的方法支持一次添加多个形状,而且添加形状时会自动判断是否已经添加过。
注:我们看到方法名带了个前缀:FCC_,这样写看似不优雅,但是对于后续的开发和使用却有很大的便利,我们统一前缀,这样在写代码时敲入前缀就能看到所有的方法,而不需要再去思考,特别是对于其它人而言,不熟悉的情况下只能去看类的定义里有哪些方法才能去调用,而不像现在这样这么方便。这是经验之谈,当然加不加前缀完全是个人自由,想怎么写就怎么写,并不会影响功能。

4.2,清空方法
我们添加一个清空当前画布中所有形状和连线的方法,用于复原:

4.3,刷新方法
我们虽然可以通过调用控件的Invalidate()方法来刷新,但是不够直观,我们直接将其封装为一个方法:

4.4,添加连线和中止连线方法
我们目前的程序支持添加连线和中止添加连线,所以我们同样开放出这两个方法:

好了,到此为止,我们的V1版画布就已经完成了,可以实现之前课程里的所有效果了。下面是完整代码,大家可查看和尝试:
点击查看代码
五、使用画布控件
我们的画布控件已经完成,下面就来看一下如何去使用它。
1,引用画布类库
因为我们的画布在独立的类库中,所以我们先引用类库:

2,添加画布控件
首先,界面与之前并无变化:

更多推荐


所有评论(0)