C#自定义事件种种
一、了解C#中的预定义事件处理机制
在写代码前我们先来熟悉.net框架中和事件有关的类和委托,了解C#中预定义事件的处理。
EventArgs是包含事件数据的类的基类,用于传递事件的细节。
EventHandler是一个委托声明如下
public delegate void EventHandler( object sender , EventArgs e )
注意这里的参数,前者是一个对象(其实这里传递的是对象的引用,如果是button1的click事件则sender就是button1),后面是包含事件数据的类的基类。
下面我们研究一下Button类看看其中的事件声明(使用WinCV工具查看),以Click事件为例。
public event EventHandler Click;
这里定义了一个EventHandler类型的事件Click
前面的内容都是C#在类库中已经为我们定义好了的。下面我们来看编程时产生的代码。
private void button1_Click(object sender, System.EventArgs e)
{
...
}
这是我们和button1_click事件所对应的方法。注意方法的参数符合委托中的签名(既参数列表)。那我们怎么把这个方法和事件联系起来呢,请看下面的代码。
this.button1.Click += new System.EventHandler(this.button1_Click);
把this.button1_Click方法绑定到this.button1.Click事件。
下面我们研究一下C#事件处理的工作流程,首先系统会在为我们创建一个在后台监听事件的对象(如果是 button1的事件那么监听事件的就是button1),这个对象用来产生事件,如果有某个用户事件发生则产生对应的应用程序事件,然后执行订阅了事件 的所有方法。
二、简单的自定义事件(1)
首先我们需要定义一个类来监听客户端事件,这里我们监听键盘的输入。
定义一个委托。
public delegate void UserRequest(object sender,EventArgs e);
前面的object用来传递事件的发生者,后面的EventArgs用来传递事件的
细节,现在暂时没什么用处,一会后面的例子中将使用。
下面定义一个此委托类型类型的事件
public event UserRequest OnUserRequest;
下面我们来做一个死循环:这个监听方法要实用化就得使用“线程”
public void Run()
{
bool finished=false;
do
{
if (Console.ReadLine()=="h")
{
OnUserRequest(this,new EventArgs());
}
}while(!finished);
}
此代码不断的要求用户输入字符,如果输入的结果是h,则触发
OnUserRequest事件,事件的触发者是本身(this),事件细节无(没有传递任何参数的EventArgs实例)。我们给这个类取名为UserInputMonitor。
下面我们要做的是定义客户端的类
首先得实例化UserInputMonitor类
UserInputMonitor monitor=new UserInputMonitor();
然后我们定义一个方法。
private void ShowMessage(object sender,EventArgs e)
{
Console.WriteLine("HaHa!!");
}
最后要做的是把这个方法和事件联系起来(订阅事件),我们把它写到库户端类的构造函数里。
Client(UserInputMonitor m)
{
m.OnUserRequest+=new
UserInputMonitor.UserRequest(this.ShowMessage);
//m.OnUserRequest+=new m.UserRequest(this.ShowMessage);
//注意这种写法是错误的,因为委托是静态的
}
下面创建客户端的实例。
new Client(monitor);
对了,别忘了让monitor开始监听事件。
monitor.run();
大功告成,代码如下:
using System;
class UserInputMonitor
{
public delegate void UserRequest(object sender,EventArgs e);
//定义委托
public event UserRequest OnUserRequest;
//此委托类型类型的事件
public void Run()
{
bool finished=false;
do
{
if (Console.ReadLine()=="h")
{
OnUserRequest(this,new EventArgs());
}
}while(!finished);
}
}
public class Client
{
public static void Main()
{
UserInputMonitor monitor=new UserInputMonitor();
new Client(monitor);
monitor.Run();
}
private void ShowMessage(object sender,EventArgs e)
{
Console.WriteLine("HaHa!!");
}
Client(UserInputMonitor m)
{
m.OnUserRequest+=new UserInputMonitor.UserRequest(this.ShowMessage);
//m.OnUserRequest+=new m.UserRequest(this.ShowMessage);
//注意这种写法是错误的,因为委托是静态的
}
}
三、进一步研究C#中的预定义事件处理机制
可能大家发现在C#中有些事件和前面的似乎不太一样。例如
private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
}
this.textBox1.KeyPress+=newSystem.Windows.Forms.KeyPressEventH
andler(this.textBox1_KeyPress);
这里使用了KeyPressEventArgs而不是EventArgs作为参数。这里使用了
KeyEventHandler委托,而不是EventHandler委托。
KeyPressEventArgs是EventArgs的派生类,而KeyEventHandler的声明如
下
public delegate void KeyEventHandler( object sender ,
KeyEventArgs e );
是参数为KeyEventArgs的委托。那为什么KeyPress事件要这么做呢,我们
可以从两个类的构造函数来找
答案
八年级地理上册填图题岩土工程勘察试题省略号的作用及举例应急救援安全知识车间5s试题及答案
。
public EventArgs();
public KeyPressEventArgs(char keyChar);
这里的keyData是什么,是用来传递我们按下了哪个键的,哈。
我在KeyEventArgs中又发现了属性
public char KeyChar { get; }
进一步证明了我的理论。下面我们来做一个类似的例子来帮助理解。 四、简单的自定义事件(2)
拿我们上面做的例子来改。
我们也定义一个EventArgs(类似KeyEventArgs)取名MyEventArgs,定义一个构造函数public MyEventArgs(char keyChar),同样我们也设置相应的属性。代码如下
using System;
class MyMyEventArgs:EventArgs {
private char keyChar;
public MyMyEventArgs(char keyChar)
{
this.keychar=keychar;
}
public char KeyChar
{
get
{
return keyChar;
}
}
}
因为现在要监听多个键了,我们得改写监听器的类中的do...while部分。改写委托,改写客户端传递的参数。好了最终代码如下,好累
using System;
class MyEventArgs:EventArgs {
private char keyChar;
public MyEventArgs(char keyChar)
{
this.keyChar=keyChar;
}
public char KeyChar
{
get
{
return keyChar;
}
}
}
class UserInputMonitor
{
public delegate void UserRequest(object sender,MyEventArgs e);
//定义委托
public event UserRequest OnUserRequest;
//此委托类型类型的事件
public void Run()
{
bool finished=false;
do
{
string inputString= Console.ReadLine();
if (inputString!="")
OnUserRequest(this,new MyEventArgs(inputString[0]));
}while(!finished);
}
}
public class Client
{
public static void Main()
{
UserInputMonitor monitor=new UserInputMonitor();
new Client(monitor);
monitor.Run();
}
private void ShowMessage(object sender,MyEventArgs e)
{
Console.WriteLine("捕捉到:{0}",e.KeyChar);
}
Client(UserInputMonitor m)
{
m.OnUserRequest+=new UserInputMonitor.UserRequest(this.ShowMessage);
//m.OnUserRequest+=new m.UserRequest(this.ShowMessage);
//注意这种写法是错误的,因为委托是静态的
}
}
多个控件公用一个事件
private void Form1_Load(object sender, System.EventArgs e)
{
int a=0;
int x=0,y=0;
for (a=0;a<=99;a++)
{
n[a] = new Button();
n[a].BackColor =Color.White;
n[a].FlatStyle = FlatStyle.Flat;
n[a].Width = panel1.Width / 10;
n[a].Left = x * n[a].Width;
n[a].Height = panel1.Height / 10;
n[a].Top = y * n[a].Height;
n[a].Name = "b" + a;
panel1.Controls.Add(n[a]);
panel1.Controls[a].MouseDown += new MouseEventHandler(this.ButtonArray
_OnClick);
x += 1;
if (x == 10)
{
x = 0;
y += 1;
}
}
}
private void ButtonArray_OnClick(object sender, MouseEventArgs e)
{
MouseEventArgs arg=(MouseEventArgs)e;
Button b1=(Button)sender;
if (arg.Button==MouseButtons.Right )
b1.BackColor=Color.White ;
else
{
//b1.BackColor =Color.White ;
b1.Image=Image.FromFile("f:\\my documents\\my pictures\\elements\\regular_s
mile.gif");
}
}
}
}
C#.NET中动态添加与删除控件
介绍
数组为共享公用功能的一组控件一起工作提供了便捷的途径。例如,一组控件可能用于显示相关的数据,或者在被点击时提供相关的行为。C#本身并不支持控件数组的建立,但是你可以通过编程复制控件数组的所有功能。本文介绍复制控件数组功能的简单组件的建立。 控件数组的主要用处有:
1,使用相同的名称与索引访问一组控件,允许用编号检索和设置数据项并且在整个数组中重复。这个功能可以使用下面的代码实现。
伪代码
myControl[myIndex].MyProperty = myValue; myControl[myIndex + 1].MyMethod
2,多个对象使用同一个事件处理程序(event handler)处理事件,在这些事件中检索和使用索引,代码如下:
伪代码
private void myControl_Click(System.Object sender, System.EventArgs e)
{
Messagebox.Show("You have clicked MyControl number " +
myControl.Index);
}
3,在运行时动态添加或者删除控件,代码如下:
伪代码
for (int i = 1; i < 6; i++)
{
//插入代码来建立控件并给属性赋值
}
C#允许你复制与控件数组相关的一些功能。例如,你能使用委托把多个对象的事件绑定到一个事件处理程序。但是,如果把这些功能合并到一个动态的、容易管理的组件中更加简便。本文将建立有下面特性的组件:
? 建立索引和排序控件的集合。将使用按钮集合来演示。
? 一个事件处理程序来处理衍生的按钮的点击事件。
? 使用索引引用控件和成员的代码。
? 给窗体动态添加和删除控件的代码。
建立项目
在本节中将建立并命名一个项目,并给该项目添加一个类。该类将封装实现控件数组的代码。
1、选择File-> New-> Project菜单打开New Project对话框。
2、从Visual C#项目列表中选择Windows Application项目模版,在Name框中输入ButtonArrayProject。
3、选择File-> Save All保存项目。
实现一个集合
ButtonArray类会处理通过一个集合的实现来保存和组织控件数组的事务。集合是包含索引对象变量列表的对象,也包含add、remove等方法和其它的操作对象。本节中将建立一个继承自System.Collections.CollectionBase(.NET框架组件中提供必要的集合功能的类)的类,并实现提供必要功能的方法。
建立继承类的过程:
1、从Project菜单中选择Add Class。
2、根据情况把类命名为ButtonArray.cs。类的代码编辑器将打开。
3、在类的声明中,指定它继承自.NET框架组件的System.Collections.CollectionBase
类。
public class ButtonArray : System.Collections.CollectionBase
{
// 省略了
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
者增加的代码
}
System.Collections.CollectionBase类为集合提供了很多必要的功能。其中包括一个跟踪集合中对象的List对象,维护集合中当前对象数量的Count属性,允许删除特定位置索引的对象的RemoveAt方法。在实现控件数组集合时会使用到它们。
因为每个控件数组与一个窗体关联,索引必须添加一个字段来保存该窗体的引用。通过建立私有的、只读字段来保存引用,可以保证每个控件数组组件只与以一个窗体关联。
为组件建立私有、只读字段
立即给类声明添加下面的代码:
private readonly System.Windows.Forms.Form HostForm;
在集合中实现的第一个方法是AddNewButton。该方法建立一个新的按钮控件并把它添加到目标窗体。你也可以使用该方法为新按钮设置初始属性。
实现AddNewButton方法
在ButtonArray类的代码编辑器中输入下面的代码:
public System.Windows.Forms.Button AddNewButton() {
//为Button类建立新的实例
System.Windows.Forms.Button aButton = new
System.Windows.Forms.Button();
//将该按钮添加到集合的内部列表
this.List.Add(aButton);
//把控件集合中的按钮添加到被HostForm字段引用的窗体
HostForm.Controls.Add(aButton);
//设置该按钮对象的初始属性
aButton.Top = Count * 25;
aButton.Left = 100;
aButton.Tag = this.Count;
aButton.Text = "Button " + this.Count.ToString();
return aButton;
}
上面的方法的功能是:
1、建立一个新按钮。
2、把它添加到内部列表和HostForm引用的窗体的控件集合。
3、设置初始属性,包括设置Tag属性来索引该按钮。你可以在这一段中添加代码为控件设置更多的属性。
4、返回新按钮,这样它就能立即被修改并指定给其它的对象引用。
你必须建立一个构造函数(组件被初始化时运行的方法),当控件数组类的一个新实例被建立时,它用来设置HostForm字段的值并把新按钮添加到窗体。可以使用下面的方式达到这个目的。
建立构造函数
为类建立构造函数。
// 使用下面的构造函数代替默认的构造函数
public ButtonArray(System.Windows.Forms.Form host)
{
HostForm = host;
this.AddNewButton();
}
构造函数需要一个参数,即放置按钮数组的窗体。它把该值指定给HostForm字段,接着类的AddNewButton方法给窗体添加一个新按钮。
暴露控件数组
现在已经建立了建立和跟踪数组中控件的途径,但是还必须把它们暴露给开发者。可以通过属性实现这个功能。我们将建立一个默认索引器基于特定按钮的索引返回它的引用。这样你就能编程使用典型控件数组中的MyButtonArray(myIndex)语法了。
建立默认属性
给组件添加下面的代码:
public System.Windows.Forms.Button this [int Index]
{
get
{
return (System.Windows.Forms.Button) this.List[Index];
}
}
实现Remove方法
现在已经建立了暴露数组中按钮的属性,可以建立从数组中删除按钮的机制了。为了从数组中删除一个按钮,必须从集合的内部List对象和窗体的Controls集合中删除它。
给组件添加下面的方法:
public void Remove()
{
//检查以确保有按钮可以删除
if (this.Count > 0)
{
' 从主窗体上的控件集合的数组按钮数组中删除最后一个
' 注意在访问数组时使用了默认属性
HostForm.Controls.Remove(this[this.Count -1]);
this.List.RemoveAt(this.Count -1);
}
}
建立公用事件处理程序
最后一步是为控件数组建立事件处理程序来处理公用的事件。在演示中,将为按钮的点击事
件建立一个方法,接着添加代码把该事件与事件处理程序关联。
建立公用事件处理程序
给组件添加下面的方法:
public void ClickHandler(Object sender, System.EventArgs e) {
System.Windows.Forms.MessageBox.Show("You have clicked button " +
((System.Windows.Forms.Button) sender).Tag.ToString()); }
该方法通过检索存储在按钮的Tag属性的索引,显示一个消息框表明哪个按钮被点击了。
该方法的参数与被处理事件的相同,对于事件处理程序是必要的。你也必须把该事件与事件处理
程序关联。
把该事件与事件处理程序关联
给AddNewButton方法添加下面的代码:
aButton.Click += new System.EventHandler(ClickHandler);
测试该项目
现在组件已经完成了,需要建立一个应用程序来测试该组件。
建立测试应用程序
1、在解决
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
管理器中,右键点击Form1并从弹出菜单中选择View Designer。 Form1的设计器被打开了。
2、给窗体添加两个按钮。
3、把这些按钮的位置调整到窗体的右侧。
4、设置这些按钮的属性:
按钮 Name Text
Button1 btnAdd Add Button
Button2 btnRemove Remove Button
5、在解决方案管理器中,右键点击Form1并从弹出菜单中选择View Code。 Form1的代码编辑器被打开了。
6、在Form1的类声明中,声明下面的控件数组对象:
//声明新的ButtonArray对象
ButtonArray MyControlArray;
7、在窗体的构造函数中,在方法结尾前添加下面的代码:
MyControlArray = new ButtonArray(this);
该语句建立了一个新的ButtonArray对象。它的参数this指向建立新ButtonArray的窗体,将成为放置按钮数组的窗体。
8、在解决方案管理器中,右键点击Form1并从弹出菜单中选择View Designer。
9、在设计器中双击btnAdd来打开btnAdd_Click事件的代码编辑器。
10、在方法btnAdd_Click中添加代码调用MyControlArray的AddNewButton方法:
//调用MyControlArray的AddNewButton方法
MyControlArray.AddNewButton();
//改变Button 0的BackColor属性
MyControlArray[0].BackColor = System.Drawing.Color.Red;
11、在解决方案管理器中,右键点击Form1并从弹出菜单中选择View Designer。
12、在设计器中双击btnRemove来打开btnRemove_Click事件的代码编辑器。
13、在btnRemove_Click方法中添加下面的代码:
// 调用MyControlArray的Remove方法
MyControlArray.Remove();
14、保存项目
测试该项目 www.w3sky.com
1、从Debug菜单中选择Start。
Form1窗体被打开,上面有三个按钮,标签分别是Add Button、Remove Button和Button 1。
2、点击Button 1。
显示了一个消息框,消息框正确地显示了索引。
3、点击几次Add Button按钮。
每次点击会给窗体添加一个新按钮。点击任何一个新按钮将导致一个正确显示该按钮索引的消息框。注意Button 0的颜色改变为红色,是btnAdd_Click事件中下面一行的结果: MyControlArray(0).BackColor = System.Drawing.Color.Red
4、点击几次Remove Button按钮。
每次点击时从窗体上删除一个按钮。
5、点击Remove Button按钮直到窗体右侧的所有按钮都被删除为止。
6、再次点击Add Button按钮。
按钮再次添加到窗体并且索引的编号正确。
结论
本文演示了怎样建立封装控件数组功能的组件。你可以看到怎样建立方法来动态地给窗体添加和删除控件,怎样通过默认属性或者索引器暴露对象。上面的代码已经实现了所有的功能,还可以通过为组件编写自定义代码来扩展控件数组。
代码:
form1.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace DAddControl
{
///
/// Form1 的摘要说明。
///
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnAdd;
private System.Windows.Forms.Button btnRemove;
ButtonArray MyControlArray;
///
/// 必需的设计器变量。
///
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
MyControlArray = new ButtonArray(this);
}
///
/// 清理所有正在使用的资源。
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成的代码
///
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
///
private void InitializeComponent()
{
this.btnAdd = new System.Windows.Forms.Button();
this.btnRemove = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnAdd
//
this.btnAdd.Location = new System.Drawing.Point(216, 0);
this.btnAdd.Name = "btnAdd";
this.btnAdd.TabIndex = 0;
this.btnAdd.Text = "Add Button";
this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click);
//
// btnRemove
//
this.btnRemove.Location = new System.Drawing.Point(216, 240);
this.btnRemove.Name = "btnRemove";
this.btnRemove.TabIndex = 1;
this.btnRemove.Text = "Remove Button";
this.btnRemove.Click += new System.EventHandler(this.btnRemove_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.btnRemove);
this.Controls.Add(this.btnAdd);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
///
/// 应用程序的主入口点。
///
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void btnAdd_Click(object sender, System.EventArgs e)
{
//from www.w3sky.com
//调用MyControlArray的AddNewButton方法
MyControlArray.AddNewButton();
//改变Button 0的BackColor属性
MyControlArray[0].BackColor = System.Drawing.Color.Red;
}
private void btnRemove_Click(object sender, System.EventArgs e)
{
MyControlArray.Remove();
}
}
}
ButtonArray.cs
using System;
using System.Windows.Forms; namespace DAddControl
{
///
/// ButtonArray 的摘要说明。
///
public class ButtonArray
:System.Collections.CollectionBase
{
private readonly System.Windows.Forms.Form HostForm;
public ButtonArray()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public ButtonArray(System.Windows.Forms.Form host)
{
HostForm = host;
//this.AddNewButton();
}
public System.Windows.Forms.Button AddNewButton()
{
//为Button类建立新的实例
System.Windows.Forms.Button aButton = new System.Windows.Forms.Button();
//将该按钮添加到集合的内部列表
this.List.Add(aButton);
//把控件集合中的按钮添加到被HostForm字段引用的窗体
HostForm.Controls.Add(aButton);
//设置该按钮对象的初始属性
aButton.Top = Count * 25;
aButton.Left = 100;
aButton.Tag = this.Count;
aButton.Text = "Button " + this.Count.ToString();
aButton.Click += new System.EventHandler(ClickHandler);
return aButton;
}
public System.Windows.Forms.Button this [int Index]
{
get
{
return (System.Windows.Forms.Button) this.List[Index];
}
}
public void Remove()
{
//检查以确保有按钮可以删除
if (this.Count > 0)
{
//from www.w3sky.com
// 从主窗体上的控件集合的数组按钮数组中删除最后一个
// 注意在访问数组时使用了默认属性
HostForm.Controls.Remove(this[this.Count -1]);
this.List.RemoveAt(this.Count -1);
}
}
public void ClickHandler(Object sender, System.EventArgs e)
{
System.Windows.Forms.MessageBox.Show("You have clicked button " +
((System.Windows.Forms.Button) sender).Tag.ToString());
}
}
}
0
0
(请您对文章做出评价)