事件及其编程方法探讨 事件驱动编程的一般方法

闁诲孩绋掗〃鍛般亹閸ф鏅柨鐕傛嫹婵犮垼顔愰幏锟�  婵炴垶鎼幏锟�  闁诲繐楠忛幏锟�

  摘要:在面向对象编程环境下,对于某种控件都给定了相应的属性及事件(Even),一般用户无法添加属性、事件及其事件驱动程序。在C#语言中,为用户提供了类的属性成员,类属性成员状态的改变,通过事件代理的关联,可以调用相应的事件处理方法。本文介绍C#语言中的属性成员、事件代理的定义,通过事件代理调用事件处理方法等技术,并通过实例程序进行必要的说明。
  关键词:属性;代理;事件;多播事件
  中图分类号:TP312 文献标识码:A
  
  1 事件及基本概念
  
  对于事件(Even),熟悉可视化编程的人员并不陌生。例如,在单击某个“按钮”后,系统应该对此“单击”事件作出相应的反映,如播放一曲MP3乐曲或显示一张图表等。
  在C#语言中,事件的发生可以由用户的操作使然;也可以由程序逻辑触发,例如类的某个对象状态发生改变将引起程序对对象状态的改变并做出相应的处理。触发事件的对象称为事件的发送者,接收事件的对象称为事件的接收者。
  C#语言的事件处理机制具有如下的特征:
  数据成员、方法、事件和属性都是类的一个成员;在.NET框架中,事件是将事件发送者与事件的接收者相关联的一种代理类,也就是事件机制是通过代理实现的。当事件被触发时,由事件的代理通知处理该事件的方法。
  
  2 C#语言中的属性成员
  
  属性常用来封装类的数据,常见的属性有对象名、字体、颜色等。使用属性的好处是使应用程序看起来更加直观。属性的用处是限制外部对类中成员变量的存取访问。
  2.1属性的定义
  C#属性定义的一般格式为:
  class 类名
  { [修饰符] 数据类型 属性名
  {访问函数体}
  }
  其中修饰符可以为:public、private、static、protected、internal、virtual、override、 abstract等。如果修饰符为abstract,则访问函数体只包含“;”,如果是其它修饰符,则访问函数体要包含访问函数体所必须的代码。数据类型表示属性成员值的数据类型。{}中的代码是执行属性过程的程序代码,一般包括get和set两个访问函数体。
  2.2 相关函数的实现
  首先要对包含get和set两个访问函数体的属性进行定义,通过 get 和 set 访问函数将专用数据成员和公共属性关联起来。根据使用情况不同,可以只用get或者set,也可以同时使用get和set。其中,get:用来读取数据成员的值;set:用来设置数据成员的值,其操作往往是“数据成员=value;”。
  2.3 类的属性编程实例
  using System;
  namespace ConAppshuxjuli
  {class point
  { int my_x, my_y ;//定义数据成员
  publicintx //实现属性成员x
  {get{ return my_x;}
   set{ my_x=value;}
  }
  public int y //实现属性成员y
  { get { return my_y;}
  set { my_y = value; }
  }
   }
   class MyApp
   { static void Main(string[] args)
   {point starting = new point();
  point ending = new point();
  //对属性成员赋值
  starting.x = 1;starting.y=3;
  ending.x = 15; ending.y = 17;
  // 对starting.x等属性成员引用
  Console.WriteLine(“起始点坐标是:
  [{0},{1}]”,starting.x,starting.y);
  Console.WriteLine(“终止点坐标是:
  [{0},{1}]”, ending.x, ending.y);
  Console.Read();
  } }}
  上述程序的运行结果为:
  
  3 事件处理程序
  
  事件处理程序编写步骤为:首先要定义一个事件代理,创建包含事件成员的类(事件类),编写事件处理方法,将事件处理方法和事件关联起来等。
  3.1 定义事件代理
  定义事件代理的格式为:
  [修饰符] delegate void 代理名([触发事件的对象,事件参数]\);
  例如:delegate voidCharEventHandler
  (Objectsender, CharEventArgs e);
  关于代理的有关内容可查阅笔者撰写的《代理及其编程方法》一文或其它有关资料。
  3.2 定义一个包含事件信息的类
  定义一个包含事件信息类的格式为:
  public class XXEventArgs:EventArgs
  {//类的具体定义}
  例如:
  public class CharEventArgs:EventArgs
   { public char CurrChar;//字符变量
  public CharEventArgs(char CurrChar)
  { this.CurrChar = CurrChar;}
  ……
  }
  3.3 创建事件类
  创建包含事件成员的类(又称为事件类),首先要定义事件成员,然后编写触发事件的方法或属性等成员。
  (1)定义事件成员的格式为:
   [修饰符] event 事件代理名 事件名
  上述事件代理名必须是在3.1定义事件代理名。
  (2)编写触发事件的方法或属性等成员
  class CharChecker
  {char curr_char;
   //定义事件成员
   public event CharEventHandler CharTest;
   //触发事件的属性
   public char Curr_Char
   { get { return curr_char; }
   set
   { if (CharTest != null)
   { CharEventArgs myevent = new
   CharEventArgs(value);
   //事件成员调用事件处理方法
  CharTest(this, myevent);
   curr_char = myevent.CurrChar;
   } } } }
  3.4 编写事件处理方法
  编写相应的事件处理方法。例如:
  static void Change_X(Object source,
   CharEventArgs e)
  { if(e.CurrChar==?x?|| e.CurrChar
   ==?X?)
   { Console.Write(“触发的字符是x ,”);
  Console.Write(“把 x 替换为:”);
   e.CurrChar =?三?;
  }
  else
   Console.Write(“触发的字符不是x ,”);
  ……
   }
  3.5 事件处理方法和事件相关联
  首先要创建事件类的对象。例如:
  CharChecker chartester = new
   CharChecker();
  再将事件处理方法与事件对象相关联,其格式为:
  事件类对象名.事件成员+=new事件代理名
  (事件处理方法名列表);
  例如:
  chartester.CharTest += new
  CharEventHandler(Change_X);
  3.6 构成完整的事件处理程序实例
  将上述步骤构成的程序代码组合起来就构成一个完整的事件处理程序。
  using System;
  namespace ConEven1
  { //创建包含事件信息的类
  public class CharEventArgs :EventArgs
  { public char CurrChar;//字符变量
  //构造函数
  public CharEventArgs(char CurrChar)
  { this.CurrChar = CurrChar; }
  class CharChecker//创建事件类
  { char curr_char;
  //定义事件成员
  public event CharEventHandler CharTest;
  public char Curr_Char//事件的属性
  { get { return curr_char; }
  set
  { if (CharTest != null)
  { CharEventArgs myevent = new
  CharEventArgs(value);
  //调用事件处理方法 CharTest(this, myevent);
  curr_char = myevent.CurrChar;
  }
  }
  }
  }
  delegate void CharEventHandler
  (bject sender, CharEventArgs e);
  class AppEvent
  { static void Main(string[] args)
  { CharChecker chartester = new
  CharChecker();//创建事件对象
  chartester.CharTest += new
  CharEventHandler(Change_X);
  chartester.Curr_Char = ‘x’;
  Console.WriteLine(“{0}”,
  chartester.Curr_Char);
  chartester.Curr_Char = ‘张’;
  Console.WriteLine(“事件处理的结果:
  {0}”,chartester.Curr_Char);
  Console.Read();
   }
   static void Change_X(Object source,
   CharEventArgs e)
   { if (e.CurrChar == ‘x’ ||
  e.CurrChar== ‘X’)
   { Console.Write(“触发的字符是 x ,”);
   Console.Write(“把 x 替换为:”);
   e.CurrChar = ‘三’;
  }
  else
  Console.Write(“触发的字符不是 x , ”);
   }
  }
   }
  }
  上述程序的执行结果为:
  
  4 多播事件及其程序实现
  
  4.1 多播事件
  多播代理具有创建方法链表的能力,当调用代理时,所有被链接的方法都会被自动调用,也就是多播可以在一次代理调用中调用方法链上的所有方法。创建多播调用链表的方法是:先实例化一个代理,然后使用“+=”运算符把方法添加到调用链表中;也可以使用“-=”运算符从调用链表中删除一个方法。
  事件也可以多播,这一特性可以使多个对象响应事件信息,还可以通过多点传送为一个事件指定多个事件处理方法,加入其它事件处理程序或删除其它处理程序和多重代理方法相同。
  4.2 多播事件处理程序的实现实例
  using System;
  namespace ConEven2
  {//定义事件信息类
   public class CharEventArgs : EventArgs{ public char CurrChar;
   //构造方法
   public CharEventArgs(char CurrChar)
  { this.CurrChar = CurrChar; }
   }
   class CharChecker//定义事件类
   { char curr_char;
  //定义CharEventHandler事件成员CharTest
  public event CharEventHandler CharTest;
   //触发事件的属性
  public char Curr_Char
   { get{ return curr_char; }
   set{ if (CharTest != null)
   { CharEventArgs args=new
  CharEventArgs(value);
  //调用事件代理
   CharTest(this, args);
   curr_char = args.CurrChar;
  }
  }
  }
  }
  //创建一个事件代理
  delegate void CharEventHandler
  (Object sender, CharEventArgs e);
  class AppEvent
  { static void Main()
  { CharChecker chartester=new
  CharChecker();//创建对象
  chartester.CharTest+=new
  CharEventHandler(Change_X);//关联
  chartester.CharTest+=new
  CharEventHandler(Change_Y);//关联
  chartester.Curr_Char = ‘x’;
  Console.WriteLine(“把x替换为:
  {0}”,chartester.Curr_Char);
  chartester.Curr_Char = ‘乙’;
  Console.WriteLine(“事件处理的结果
  :{0}”, chartester.Curr_Char);
  chartester.Curr_Char = ‘y’;
  Console.WriteLine(“把y替换为:
  {0}”, chartester.Curr_Char);
  Console.Read();
  }
  static void Change_X(Object source,
   CharEventArgs e)
  { if (e.CurrChar==‘x’||e.CurrChar==‘X’)
  { Console.Write(“触发的字符是x ,”);
  e.CurrChar = ‘?’;
  }
  else
   Console.Write(“触发的字符不是 x , ”);
   }
  static void Change_Y(Object source,
   CharEventArgs e)
   { if(e.CurrChar==‘y’|| e.CurrChar== ‘Y’)
  { Console.WriteLine(“触发的字符是 y ”);
   e.CurrChar = ‘#’;
  }
   else
  Console.WriteLine(“触发字符不是 y ”);
   }
  }
  }
  上述程序的执行结果为:
  
  5 结束语
  
  其实,C#系统将事件视作一个代理类,并根据系统提供的各种状态自动实现跟踪和处理。当对象的某个状态发生了变化,代理就会自动调用,并执行代理的方法。事件和代理一样也支持多播,一个事件发送者可以同时触发多个处理事件的方法。
  
  参考文献
  [1]刘瑞新主编. C#网络编程及应用[M]. 北京: 机械工业出版社, 2005.
  [2]谢桂华, 魏亮等.Visual C#高级编程范例[M]. 北京: 清华大学出版社, 2004.
  [3]邵鹏鸣编著. Visual C#程序设计基础教程[M]. 北京: 清华大学出版社, 2005.
  [4]唐大仕编著. C#程序设计教程[M]. 北京: 清华大学出版社, 2003.

闂傚倷绀侀幖顐﹀磹缁嬫5娲Ω閳哄倸浠ч梻浣哥仢椤戝洭銆呴悜鑺ョ叆婵犻潧妫欓崳褰掓煛閸滃啯瀚�
闂傚倷绶氬ḿ鑽ゆ嫻閻旂厧绀夐幖娣妼閸氬綊骞栧ǎ顒€濡兼俊鐐扮矙閺屾洘绻濇惔锝呭弗闂佹悶鍊ч幏锟�
婵犵數濮伴崹鐓庘枖濞戞氨鐭撻柟缁㈠枛閺勩儲淇婇妶鍛櫣缂佺媴缍侀弻鐔兼焽閿曗偓婢ь喗銇勯顒佸
闂佽娴烽弫濠氬磻婵犲洤绐楅柡鍥╁枔閳瑰秴鈹戦悩鍙夋悙闁活厽顨婇弻銊╂偆閸屾稑顏�: daibi881
濠电姷鏁搁崕鎴犵礊閳ь剚銇勯弴鍡楀閸欏繘鏌i幇顒佲枙闁搞倖顨嗛妵鍕籍閸ヨ泛鏁界紓浣筋嚙濡鍩為幋锕€纾兼繝闈涙祩濡嫰鎮楀▓鍨灍闁诡喖鍊垮顐㈩吋閸涱垱娈曢梺鍛婂姈閸庡啿鈻撳⿰鍛=闁稿本鐟чˇ锔戒繆椤愶絾鈷掗柤娲憾閺佸秹宕熼鈧弸鍌炴⒑閹稿海绠撻悗姘嵆閹即骞樼紒妯煎幈濠电娀娼ч幊妯侯瀶閻戣姤鐓冪憸婊堝礈閵娾晛绠柨鐕傛嫹
闂傚倷鐒﹀鍧楀储瑜版帒纾块柛顭戝亞椤╂煡鏌i幇闈涘妞も晜鐓¢弻銊╂偆閸屾稑顏�
濠电偛顕慨鍨仚闂佹悶鍔岄崐鍨嚕婵犳艾唯鐟滃海绮诲▎鎾寸厱闊洤顑呮俊浠嬫煛鐎n亜鏆g€规洦浜炴禒锔剧驳鐎n倣鈺呮⒑閸涘﹤閲滈柟鍑ゆ嫹
闂傚倸鍊哥€氼參宕濋弽褜娓婚柛宀€鍋為崑瀣⒑椤愶絿銆掓鐑囨嫹: 5闂備胶枪妤犲繘骞忛敓锟�/缂傚倷璁插Σ鍕箯閿燂拷闂備礁鎲″玻鍧楀窗瀹ュ鍋濋柨鐕傛嫹10闂備胶枪妤犲繘骞忛敓锟�
闂備線娼荤拹鐔煎礉鎼淬劌鍚归幖娣妼缂佲晜銇勯弽銊ф噮閻㈩垽鎷�
闂備浇澹堟ご绋款潖婵犳碍鐒鹃悗鐢电《閸嬫捇鐛崹顔句痪濠电姭鍋撻柨鐕傛嫹
濠电姰鍨煎▔娑氱矓閹绢喖鏄ユ俊銈呮噹缁狅綁鏌熼柇锕€澧い顐ゅ█閺屻劌鈽夐搹顐㈩伓
濠电偛顕慨鍨仚闂佹悶鍔岄崐鍧楃嵁鐎n喖绠涙い鎺嗗亾妞ゎ偆濞€閺屾稑顫濋鈧崵杈╃磼鏉堛劎绠為柟宕囧枛婵$兘鏁傞弬銈夌崪婵犵數鍋涢ˇ鏉棵洪幋鐐电闁搞儺鍓氶崑銊╂煏婵犲海鍘涢柛銈囧仱閺屻倖娼忛妸锔规嫽闂備緡鍠栭顓㈠焵椤掆偓缁犲秹宕归崫鍕惰€块柨鐕傛嫹 闂佽楠哥粻宥夊垂閸濆嫸鑰块柛銉戝苯娈銈嗘椤斿﹦鎹㈤崱娑欑厱婵炲棙鐟︾€氾拷 zaidian88 闂傚倸鍊甸崑鎾绘煙缁嬪潡顎楅柣锕佸吹閳ь剛鏁婚崑濠囧窗閺囩喓鈹嶅┑鐘叉搐閻鈧懓瀚妯兼媼閹绘帩鐔嗛悹楦挎瀛濋梺绯曟櫔閹凤拷 濠电偞鎸婚懝楣冨Φ濡壈濮虫い鎺戝缁犳牠鏌曟繝蹇涙闁稿绻勭槐鎺楀箟鐎n偄顏� 闂備胶鎳撻悘姘跺箰閸濄儲顫曢柟瀛樼箥閸ゆ銇勯弮鍥跺敽缂佷紮鎷�
闂備線娼荤拹鐔煎礉鎼淬劌鍚归幖娣妼缁秹鏌涢锝嗙闁挎稓鍠栭弻銊モ槈濞嗘帒顥濋梺鐟板暱濡瑧绮欐径鎰劦妞ゆ帒瀚崵濠囨煕閹邦剙绾ч柛锝庡灠闇夋繝濠冨姈鐎氾拷 9:00-12:30 14:00-18:30 闂備礁鎲$粙蹇涘礉瀹€鍕煑闁跨噦鎷� 9:00-12:30
闁诲海鏁婚崑濠囧窗閺囩喓鈹嶅┑鐘叉搐缂佲晜銇勯弽銊ф噮閻㈩垱绋戦埥澶愬箼閸愩劌浼庣紓浣介哺缁诲嫰骞忛悩鑼殝闁哄娉曢幉锕傛⒑缁嬭法绠插┑鐐诧工铻為悗闈涙憸閻滅粯淇婇妶鍌氫壕閻熸粌搴滈幏锟�
闁诲海鏁婚崑濠囧窗閺囩喓鈹嶅┑鐘叉搐缂佲晜銇勯弽銊ф噮閻㈩垱绋戦埥澶愬箼閸愩劌浼庣紓浣介哺缁诲嫰骞忛悩鑼殝闁哄娉曢幉锕傛⒑缁嬭法绠插┑鐐诧工铻為悗闈涙憸閻滅粯淇婇妶鍌氫壕閻熸粌搴滈幏锟�
濠电姷顣介埀顒€鍟块埀顒€缍婂畷鎴濐吋閸滀礁鏅犻梻濠庡亽閸樺墽鏁☉銏″仯闁规媽鍩栫€氾拷,闂佽崵濮村ú銊╁蓟婢舵劕鐒垫い鎺嶇婵洨绱掗崫鍕挃缂侇喖鐏氬鍕節閸曨収鈧偓,闂備礁鎲$敮鎺懨洪妶鍥e亾閿濆嫮鍔嶇紒鍌氱Ф娴狅妇绱掗姀鐘辫繕濠电偛顕慨鍨仚闂佹悶鍔岄崐鎸庝繆閹绢喗鏅搁柨鐕傛嫹
闂備浇銆€閸嬫挻銇勯弽銊ф噮閻㈩垱鐩弻鐔衡偓娑櫭慨鍥р攽椤曞棙瀚� 闁诲氦顫夐悺鏇犱焊椤忓牏宓侀煫鍥ㄦ惄閸ゆ淇婇妶鍛伌闁搞倕顦甸弻锟犲磼濮橆厼绐涢梺缁樼箞閺€鍗烆嚗閸曨偒鍚嬮柛娑卞幘閸橆剟姊洪崫鍕垫Ц闁哥喐娼欓‖濠囨晸閿燂拷