1.创建一个自定义控件

这篇文章是 C#自定义控件开发 系列的第一篇文章 其实如果你看过[GDI+程序设计]这本书的话 我这一系列的文章你也不用看了 因为自定义控件的开发 和 GDI 的很多东西我都是从这本书上学习到的 好了话不多说 我把这本书的上传到了百度网盘 复印版虽然不是很清晰 不过还是能看的

http://pan.baidu.com/s/1qWAWm8c([GDI+程序设计])

下面开始第一篇:如何创建一个自定义控件

我们打开vs新建一个WinForm项目 然后右键工程【添加(Add)】选项里面可以看到有 【用户控件(User Control)】

当我们添加后发现出来了这个东西:

http://yandex.ru/clck/jsredir?from=yandex.ru%3Bsearch%3Bweb%3B%3B&text=&etext=1218.ksNbuUr7OYKWwIf-r2I-GCrv7vGY64PoN0JBaBgDFMc.31a7f9435f6581d1caf68475ce87d70c4c3ffa3f&uuid=&state=_BLhILn4SxNIvvL0W45KSic66uCIg23qh8iRG98qeIXmeppkgUc0YD4hgzqAYr5iuWBiLZQy-rY&data=UlNrNmk5WktYejR0eWJFYk1LdmtxbFpaTjYtLWdkZHM0LU9fR1YzaWxTcWtWLXdxVDFNWnpoVHd2R2NQelhUM1JTNUctS2dULUpwTTlvRFRGOTh1dnY3RUluVDFLX0FMcVVnZHgtQlFhcnFfbVhOV1JsdzVnUQ&b64e=2&sign=c55137935c3ffe5dce765f2ccb80491f&keyno=0&cst=AiuY0DBWFJ7IXge4WdYJQYpgPUyh7uQlb0r7Tiy8IUEzRFpA02Tj-xV9nt3jvEEUyTyZ1yDJ9VBA2AFyvZ7uJMofO9cRvul-gcjFHrRvxUQUJ6hTZRW0HNAZ8WbUPOZWD-yZvWfmTsid0ZwyGZSTkw&ref=orjY4mGPRjk5boDnW0uvlrrd71vZw9kp5uQozpMtKCWAB4NbWhozjjOh7PJtYgyuFPPuI6aCReI995shFwFgkV510S4z_PpQfRSU2JRCjok&l10n=ru&cts=1477203192860&mc=6.15626913549

可以看出这东西几乎和窗体设计一模一样 只是少了一个窗体的边框 可以在上面自由的添加控件 而且在我们添加好用户控件的同时 左边的工具栏上呈现出了我们添加好的用户控件

下面我们来为刚才添加的那个用户控件 添加一点代码 我在上面放了一个button 然后双击写了一段代码 弹出一个Hello World

private void button1_Click(object sender, EventArgs e) {
    MessageBox.Show("Hello World");
}
然后我们从左边把用户控件添加到窗体上运行 然后点击那个button1

其实 这本身是一个没有多大意义的例子 而且在接下来的文章里面 几乎也不会讲到 【用户控件(User Control)】

因为在我的眼里 用户控件 一般用来用作复合控件 也就是把现有的控件放在一起实现一些功能 然后变成一个新的控件 也就是一个控件的集合 比如我们可以做这样一个控件:

假设 我们现在有个程序 xxx管理系统 程序要从数据查询数据上来 由于数据可能很多 所以我们窗体上不可能显示出所有的数据 所以我们可能需要对数据 进行一下分页  而这个分页可能很多窗体上都要用到 所以这个时候我们可以做一个复合控件 然后在需要的窗体上把这个控件加上去 这样就不用在每个窗体上都去拖出同样的一堆控件了 至于这样做 怎么触发一些事件 在之后的文章中介绍 比如上面这个符合控件 我点了跳到最后一页 怎么让添加这个控件的窗体知道 我点下了跳到最后一页

对于 用户控件 这里就暂时讲这么多 因为 接下来的文章中 主要讲直接继承 Control 或者 从现有控件派生一个控件

下面来看另一个创建一个自定义控件的方式 我们新建一个类 然后让他继承 Control 或者你也可以直接 依然添加一个用户控件 然后去修改代码 让他继承 Control

public class MyControl : Control
{

}

注意 如果你是直接新建一个类 然后继承 Control 的可能会报错 因为需要引用 System.Windows.Forms 新建类的时候上面引用不会生成这个(我是vs2010 .net 2.0)

如果你是添加的用户控件 然后去修改代码继承 Control 的话不会纯在 System.Windows.Forms 的问题 不过如果有其他问题报错的话 你把报错的代码删除就是了

下面来看看这图:

可以看到 我刚才创建的 MyControl 和 最开始创建的 UserControl1 的图标和普通的类的图标不一样  而UserControl的结构似乎长得有点像 Form的结构 因为 展开下面都有一个 Name.Designer.cs 和 Name.resx 所以正如刚才上面说以 在做用户控件的时候 几乎 和做窗体的时候一样 只是 用户控件没有窗体的边框而已 而MyControl则没有 Name.Designer.cs(可能会有 Name.resx);

还有一个问题 我们双击普通的类文件的时候 能直接看到类的代码 而窗体 还有 刚才创建的用户控件 双击的时候 都能出现窗体设计起  然后双击刚才我创建的 MyControl.cs 出来的尽然是没有见过的东西 是的 直接继承Control不像UserControl或者Form那样 是没有窗体设计器的 UserControl 和 Form 都是容器 在设计时期可以可视化的向其添加子控件 所以他们在设计时可以有设计器 而 Control 没有继承容器控件 不能直接拖一个控件进去 所以也就没有必要需要设计器(以上言论纯属个人YY - -!)(注:如果的类是继承的Control左边工具栏同样会出现你的控件 如果你发现没有或者你新建的类图标还是普通类的图标 可能是vs的延迟你捣鼓两下就行了 如果还是那样 你重启一下vs 一般情况下是不会出现这个问题的 vs检测到你继承了Control或者其他控件 会立马有反映的)

言归正传 就算没有设计器 可以看到 右下角的属性窗口什么的还是可以正常时候的(属性窗口那些都是作为一个控件必备的东西 不要觉得奇怪 为什么继承了一个Control居然有属性窗口 还有那么多东西 其实你可以看到很多属性Text Height Width...和一些事件 Click KeyDown... 这些东西都是你可以直接用的)  现在有个问题 如果我们就这样 啥也不做 把这个控件 添加到窗体上是啥效果 其实你可以看到 如果啥都不做 就这样把控件添加到窗体上去 他默认是一个按钮大小的四四方方的东西 因为我们啥也没有做 所以他大小是默认的 背景色是默认的

下面 我们来添加一段代码 让他有个样子 我们在属性窗口找到 paint 事件 然后写上如下代码:

private void MyControl_Paint(object sender, PaintEventArgs e) {
    //如果Brushes报错 需要引用 System.Drawing;
    e.Graphics.DrawString("Hello World", this.Font, Brushes.Red, 0, 0);
}

这段代码的意思就是 在当前控件坐标(0,0)的位置 绘制一段文字"Hello World" 文字的颜色用红色 文字的字体是当前控件的字体(属性窗口可以看到)[对于GDI的一些东西 今后的文章里面不会过多描述 因为这一系列的文章主要讲 控件的开发 如果对GDI不怎么熟悉 建议先去了解一下 或者下载我上传的那本电子书看也可以]

到这里请注意 如果你现在就从左边把控件添加到窗体上 你可能会看不到效果如果你是直接新建类继承Control的话 如果你的代码是类似这样的:

public class MyControl : Control
{

    private void InitializeComponent() {
        this.SuspendLayout();
        // 
        // MyControl
        // 
        this.Paint += new System.Windows.Forms.PaintEventHandler(this.MyControl_Paint);
        this.ResumeLayout(false);

    }

    private void MyControl_Paint(object sender, PaintEventArgs e) {
        //如果Brushes报错 需要引用 System.Drawing;
        e.Graphics.DrawString("Hello World", this.Font, Brushes.Red, 0, 0);
    }
}
为什么会没有反映? 我们把刚才第一个的UserControl的代码:
public partial class UserControl1 : UserControl
{
    public UserControl1() {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e) {
        MessageBox.Show("Hello World");
    }
}
在这里 我们看到都有InitializeComponent方法的存在 而这个方法 一般在 Name.Designer.cs 这个文件里面 UserControl 会有这个文件 由于我们直接继承的Control没有这个文件 所以这部分代码自动生成的时候 直接生成到了我们的 类里面 但是这个不是重点 重点是我们没有去调用这个方法、、仔细想想 是不是UserControl 或者 Form里面 我们去查看代码 都有类是
public XXXXXX(){
    InitializeComponent();
}

都会有这个代码 这个是自动生成的构造器 构造的时候去调用那个方法初始化一些信息 而我们直接继承的Control的类 vs没有为我们生成这样的方法 因为在创建类的时候 vs是不会给我们的类生成构造器的 而vs也不知道我们将把这个类继承Control作为控件使用 然后为它生成一个构造器并调用初始函数  所以你得自己写个构造器然后去调用初始函数就行了

所以一般情况下 我直接继承Control或者其他控件的时候 我都不喜欢用右下角的属性窗口 去做事情 而是直接override 就像:

public class MyControl : Control
{
    protected override void OnPaint(PaintEventArgs e) {
        //如果Brushes报错 需要引用 System.Drawing;
        e.Graphics.DrawString("Hello World", this.Font, Brushes.Red, 0, 0);
        base.OnPaint(e);
    }
}

然后现在把控件 添加到窗体上就能看到 红色的 Hello World 了:

最后关于Paint说明一点 对于Paint事件或者OnPaint 这个是由系统去触发的

以前看到很多人问 为什么我在窗体加载的时候 里面绘制图像的代码没有起作用 或者 为什么我窗体最小化后再打开 上面画的图都不见了 觉得有点让人难以理解 这是正常的 你用g.DrawXXX()绘制的任何东西都是一次性的 并不是永久生效的 什么意思呢 比如现在窗体上有个按钮 你在Click中在窗体上绘制了一个矩形框 你也确实看到有个矩形框在上面 但是你最小化再打开 或者把窗体拖动到边缘的时候 再托回来发现 绘制的矩形框没有了这是为什么呢?因为最小化后窗体从桌面消失 然后再打开的时候 那么windows系统就得在说面把你的窗体呈现出来 而这个呈现的过程就是在桌面上画出一个窗体来 由于系统他只知道你有一个窗体和一个按钮 那么windows就在桌面上绘制一个你的窗体 然后再绘制一个按钮到窗体上去 windows并不知道 在这之前你还在窗体上绘制了一个矩形框 那么要如何解决这个问题呢 所以说windows为我们的控件或者窗体提供了Paint事件 然后我们把需要绘制的东西写在Paint事件中 这样的话windows就不用理会我们在窗体上绘制了什么了 当windows觉得应该要绘制窗体的时候 就发出WM_PAINT消息来出发Paint事件 然后用户把绘制的代码写在Paint事件中 那么绘制的图像就不会丢失了

第一篇就到这里 虽然现在还没有看到实质性的东西 后面会我也会慢慢写文章弄点有实质性的东西出来 这里只是一个引入 一个开篇而已


添加时间:2014-03-20 03:48:32 编辑时间:2016-10-23 10:19:04 阅读:1639 
C#自定义控件开发 C#控件开发
还没有人留言 要不你来抢一个沙发?
  • 编写评论

      我觉得区分大小写是一个码农的基本素质
[访问统计] 今天:39 总数:159071 提示:未成年人 请在大人陪同下浏览本站内容 还有:世界上最帅的码农 -> 石头 RSS:http://st233.com/rss Powered by -> Crystal_lz