C#中的自定义控件中的属性、事件及一些相关特性的总结(转)
今天学习了下C#用户控件开发添加自定义属性的事件,主要参考了MSDN,总结并实验了一些用于开发自定义属性和事件的特性(Attribute)。
在这里先说一下我的环境:
操作系统:Windows7旗舰版(Service Pack 1)
VS版本:Microsoft Visual Studio Ultimate 2012,版本 11.0.50727.1 RTMREL
.NET Framework版本:4.5.50938
C#版本:Visual C# 2012
一、准备工作
1、建立一个C#窗体应用程序,主窗体起名为FormMain,向解决方案中再加入一个用户控件,起名为TestUserControl
2、在TestUserControl中放一个按钮,取名为btnTest
3、控件做好后,会出现在【工具箱】内
4、将控件拖拽到一个窗体(Form)上就可以使用了,取名testUserControl1。这个名字是VS默认取的,即首字母小写,最后补上数字作为序号。
二、添加自定义属性
在TestUserControl类中,添加下面的代码:
/// <summary>
/// 按钮名称
/// </summary>
public string ButtonName
{
get
{
//TODO
return btnTest.Text;
}
set
{
//TODO
btnTest.Text = value;
}
}
代码添加完毕后,在FormMain上加入的testUserControl1的属性中,就会出现BtnName了
三、添加自定义事件
在TestUserControl类中,添加下面的代码:
/// <summary>
/// 事件
/// </summary>
public event EventHandler BtnTestClick;
/// <summary>
/// 测试按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnTest_Click(object sender, EventArgs e)
{
if (BtnTestClick != null)
{
//TODO
BtnTestClick(sender, e);
}
}
代码添加完毕后,在FormMain上加入的testUserControl1的事件中,就会出现BtnTestClick了
在FormMain的代码中实现这个函数
private void testUserControl1_BtnTestClick(object sender, EventArgs e)
{
MessageBox.Show(sender.ToString() + "\r\n" + e.ToString());
}
这时运行程序,点击控件testUserControl1内的按钮btnTest,就会有下面的效果:
四、几个特性(Attribute)
1)DefaultEvent和DefaultProperty:指定自定义控件的默认事件和默认属性
DefaultEventAttribute(MSDN)可以用来指定组件的默认事件,如在TestUserControl类上面加入代码
[DefaultEvent("BtnTestClick")]
那在Form编辑界面,双击控件testUserControl1就会自动进入testUserControl1_BtnTestClick事件。
这里再说明一下,C#中的System.Windows.Forms.Control类代码如下:
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ComVisible(true)]
[DefaultEvent("Click")]
[DefaultProperty("Text")]
[Designer("System.Windows.Forms.Design.ControlDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
[DesignerSerializer("System.Windows.Forms.Design.ControlCodeDomSerializer, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.ComponentModel.Design.Serialization.CodeDomSerializer, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
[ToolboxItemFilter("System.Windows.Forms")]
public class Control : Component, IDropTarget, ISynchronizeInvoke, IWin32Window, IBindableComponent, IComponent, IDisposable
{ /* ... */ }
这里可以看到DefaultEvent的值为“Click”,这也就是为什么拖入Form的按钮(Button),在双击后会进入它的Click事件:
private void button1_Click(object sender, EventArgs e)
对于不希望以Click事件作为默认事件的控件来说,要手动指定该控件的DefaultEvent特性,如复选框(CheckBox)的声明:
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ComVisible(true)]
[DefaultBindingProperty("CheckState")]
[DefaultEvent("CheckedChanged")]
[DefaultProperty("Checked")]
[ToolboxItem("System.Windows.Forms.Design.AutoSizeToolboxItem,System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public class CheckBox : ButtonBase
{ /* ... */ }
这里的DefaultEvent被写上了“CheckedChange”,因此在Form的编辑界面,双击复选框时默认进入的编辑事件为
private void checkBox1_CheckedChanged(object sender, EventArgs e)
自定义的控件(直接继承自UserControl),如果不添加这个属性,在编辑界面双击后进入的事件是Load事件。
类似的特性还有DefaultProperty,DefaultPropertyAttribute(MSDN)可以被用来指定组件的默认属性。指定默认属性后,当用户在Form里单击这个控件时,将在属性浏览窗口中自动选定该属性:
[DefaultProperty("BtnName")]
2)Browsable:设置控件某一属性或事件是否出现在“属性”窗口中
BrowsableAttribute(MSDN)指定某一属性或事件是否应在“属性”窗口中显示,如在属性BtnName上添加代码:
[Browsable(false)]
则控件testUserControl1的属性界面就不会出现BtnName的设置了,下图红线部分为之前BtnName所在的位置
如果某属性或事件没有添加Browsable特性,那么该属性或事件也可以在“属性”窗口中看到。这里还要说明以下,Browsable只能决定某属性或事件在“属性”窗口内的可见性,Browsable被置为false的属性和事件,仍可以在编辑器中通过代码中使用。
3)Description:指定控件某一属性或事件出现在“属性”窗口中的说明文字
DescriptionAttribute(MSDN)用于指定控件的某一属性或事件出现在“属性”窗口中的说明文字
如在BtnName上添加下面代码:
[Description("设置按钮上显示的文字")]
也可以带上Browsable特性一起使用:
[Browsable(true)]
[Description("设置按钮上显示的文字")]
或写在一对方括号里,用逗号隔开:
[Browsable(true), Description("设置按钮上显示的文字")]
在“属性”界面中看到的说明文字,效果如下:
4)EditorBrowsable:指定某一属性或方法在编辑器中可见
EditorBrowsableAttribute(MSDN)指定某个属性或方法在编辑器中可以查看。
EditorBrowsableAttribute的构造函数如下:
public EditorBrowsableAttribute(EditorBrowsableState state);
其中,EditorBrowsableState是一个枚举(enum),这个枚举共有三个值,分别是Always、Never和Advanced
Always:该属性或方法在编辑器中始终是可浏览的
Never:该属性或方法始终不能在编辑器中浏览
Advanced:该属性或方法是只有高级用户才可以看到的功能。 编辑器可以显示或隐藏这些属性
前面两个都好理解,第三个Advanced着实会让人一头雾水(什么才叫“高级用户”?)。后来查了一些资料,才知道对于高级成员的可见性,可以在“工具”菜单下的“选项”中进行配置。
(在这里感谢大神在social.msdn.microsoft.com上的 解答 )
如果勾选了“隐藏高级成员”,那么用代码“[EditorBrowsable(EditorBrowsableState.Advanced)]”标记的属性,将不能在IDE中自动显示。但这也仅仅是不自动显示而已,如果在代码中真的调用了不可见的属性,编译不会报错,运行也不会有问题。
如下图:BtnName被标记为“EditorBrowsableState.Never”,因此这个属性不会出现在VS的智能提示(学名叫IntelliSense)中,但如果写到代码里,却没有问题。
需要注意的是,这种隐藏只有在该控件代码为当前解决方案不可见时有效,也就是说,如果这个控件的实现代码就在你的解决方案内,EditorBrowsable并不能保证用户看不见这个属性。但如果这个控件时被放在一个dll文件中添加引用到当前的解决方案中,EditorBrowsable特性才能按其文字描述中说明的那样起作用。
5)DesignerSerializationVisibility:代码生成器生成组件相关代码的方式
DesignerSerializationVisibilityAttribute(MSDN)用于指定在设计时序列化组件上的属性时所使用的持久性类型。
参数为DesignerSerializationVisibility类型的枚举:
Hidden:代码生成器不生成对象的代码
Visible:代码生成器生成对象的代码
Content:代码生成器产生对象内容的代码,而不是对象本身的代码
这个说法一眼看上去并不易理解,因此我决定还是用两个具体例子说明一下:
1、Hidden与Visible、Content的不同
还是以我们上面的BtnName属性为例,参数为【DesignerSerializationVisibility.Hidden】的情况
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public string BtnName
{
get
{
return btnTest.Text;
}
set
{
btnTest.Text = value;
}
}
将控件拖入FormMain的窗体设计器中,可用在文件FormMain.Designer.cs中看到:
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.testUserControl1 = new ControlTest.TestUserControl();
this.SuspendLayout();
//
// testUserControl1
//
this.testUserControl1.Location = new System.Drawing.Point(33, 46);
this.testUserControl1.Name = "testUserControl1";
this.testUserControl1.Size = new System.Drawing.Size(134, 77);
this.testUserControl1.TabIndex = 0;
// ...
}
将BtnName上方的特性DesignerSerializationVisibilityAttribute的参数改为【DesignerSerializationVisibility.Visible】或【DesignerSerializationVisibility.Content】后,函数InitializeComponent()中的代码会有不同:
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.testUserControl1 = new ControlTest.TestUserControl();
this.SuspendLayout();
//
// testUserControl1
//
this.testUserControl1.BtnName = "button1";
this.testUserControl1.Location = new System.Drawing.Point(36, 32);
this.testUserControl1.Name = "testUserControl1";
this.testUserControl1.Size = new System.Drawing.Size(134, 77);
this.testUserControl1.TabIndex = 0;
// ...
}
可用看出,区别就在下面这行代码:
this.testUserControl1.BtnName = "button1";
使用了Hidden就没有,使用了Visible就会有(使用了Content也会有)
使用了Hidden后,在“属性”界面中,无论怎么修改BtnName属性的值,编译时编译器都不会理睬这个值,而是使用默认值(这个例子里面就是button1)。使用了Hidden后,即使在FormMain.Designer.cs里手动把上面那行赋值的代码加上,这行代码在程序重新编译后还是会消失。
2、Visible与Content的不同
Content被用在可以序列化的集合,例如System.Windows.Forms.DataGridView类(数据表格)
//
// 摘要:
// 获取一个包含控件中所有列的集合。
//
// 返回结果:
// 一个 System.Windows.Forms.DataGridViewColumnCollection,包含 System.Windows.Forms.DataGridView
// 控件中的所有列。
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor("System.Windows.Forms.Design.DataGridViewColumnCollectionEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
[MergableProperty(false)]
public DataGridViewColumnCollection Columns { get; }
IDE只是生成这些属性中包含组件的代码,而不会生成属性本身的代码。在使用IDE添加各个DataGridViewTextBoxColumn时,各个DataGridViewTextBoxColumn的代码会被放在FormMain.Designer.cs文件中,而有关Columns属性本身只会在在函数InitializeComponent()中生成这样一段代码:
this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.Column1,
this.Column2,
this.Column3});
6)其他特性
其他的特性还有许多(如Localizable被用于指定属性是否可本地化、DefaultValue用于为属性指定另一个“默认值”等),如只是初步了解可以去查看VS从程序集 System.Windows.Forms.dll中反射出的各控件、控件属性、控件事件的声明和摘要(就是声明上面的绿字),更详细的描述可以去参考MSDN。
END
C#中的自定义控件中的属性、事件及一些相关特性的总结(转)的更多相关文章
- Winform中用户自定义控件中外部设置子控件属性的方法
假设我们新建立一个用户自定义控件,由一个lable1和pictureBox1组成 此时我们在外部调用该控件,然后想动态改变lable1的值,我们该怎么办? 假设实例化的用户控件名为UserContro ...
- [翻译]使用Swift在Xcode中创建自定义控件
使用Swift在Xcode中创建自定义控件 原文 IBDesignable and IBInspectable With IBDesignable and IBInspectable, develop ...
- winform自定义控件中其他遮挡控件点击事件
自定义控件在其他窗口调用时,里面的lable阻挡了控件的点击事件 解决方法 自定义控件中lable的 点击事件 private void Lable1_Click(object sender, Eve ...
- wpf自定义控件中使用自定义事件
wpf自定义控件中使用自定义事件 1 创建自定义控件及自定义事件 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 2 ...
- WPF中XAML的触发器的属性,事件 都有那些?以及如何寻找
在编写XAML的触发器时,会有属性,事件. 那么这些都是哪里来的呢? 属性,是附加属性或者依赖属性 事件,那就是事件. 如何寻找呢? 很简单,在想要使用的触发器的对象上(也就是有光标的时候)按下F12 ...
- js 中HTML的 onkeycode 和onkeydown属性事件
<!DOCTYPE html><html><head><script>function displayResult(){var x=document.g ...
- android 自定义控件中获取属性的三种方式(转)
第一种方法,直接设置属性值,通过attrs.getAttributeResourceValue拿到这个属性值. (1)在xml文件中设置属性值 <com.example.activity.Ico ...
- Android中的自定义控件(二)
案例四: 自定义开关 功能介绍:本案例实现的功能是创建一个自定义的开关,可以自行决定开关的背景.当滑动开关时,开关的滑块可跟随手指移动.当手指松开后,滑块根据开关的状态,滑到最右边或者滑到 ...
- XAML: 自定义控件中事件处理的最佳实践
在开发 XAML(WPF/UWP) 应用程序中,有时候,我们需要创建自定义控件 (Custom Control) 来满足实际需求.而在自定义控件中,我们一般会用到一些原生的控件(如 Button.Te ...
随机推荐
- POJ 3071 Football 【概率DP】
Football Football Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3734 Accepted: 1908 ...
- MongoDB笔记(三):Document 数据插入、删除、更新
实例数据库caliven.集合users 一.插入文档 1.插入文档 db.[documentName].insert({}) 2.批量插入文档 .shell 这样执行是错误的db.[document ...
- 编写C函数的技术-《lua程序设计》 27章 学习
1.数组操作 void lua_rawgeti(lua_State * L ,int index,int key) void lua_rewseti(lua_State * L,int index,i ...
- Problem-1001:Sum Problem
Sum Problem Sample code : #include <stdio.h> int main() { int i,n; int sum; while(scanf(" ...
- asp.net+mvc+easyui+sqlite 简单用户系统学习之旅(二)—— easyui的简单实用
下面开始在UserManager.Web中利用easyUI构建web. 1. 先删除自带的controllers.models和views(里面的shared和web.config可以保存)下面的文件 ...
- postman --发送json请求
转自: http://blog.csdn.net/wangjun5159/article/details/47781301 简介: postman是一个很好的http模拟器,在测试rest服务时是很好 ...
- elasticsearch 索引设置
索引设置 你可以通过很多种方式来自定义索引行为,你可以阅读Index Modules reference documentation,但是: 提示: Elasticsearch 提供了优化好的默认配置 ...
- FPGA和DSP间基于SRIO的高速通信系统设计
作者:陈婷,岳强,汪洋 解放军信息工程大学 摘要: 现代信号处理系统通常需要在不同处理器之间实现高速数据通信,SRIO协议由于高效率.低延时的特性被广泛使用.本文研究了在FPGA和DSP两种处理器之间 ...
- abp的权限与导航菜单的关系
原来以为各是各的,所以就有了第一个版本.Getallmentus.然后注入了role,当然失败了.获取所有的菜单.一直在思考在什么地方设置菜单是否展示呢? 后面看了源码.才发现自己错了. UserNa ...
- csla 与高cpu
在项目中一直使用csla 4.13. 项目一直正常,但是偶尔会出现iis占用的cpu 突然100%, 后面客户量大的情况,加入了缓存的机制.100%的情况出现的更多了. 当时有数据库死锁的原因.cpu ...