. Net event model tutorial (1)

Source: Internet
Author: User

Directory

  • Concepts of events and event handlers
  • Problem description: a task that takes a long time to complete
  • High Coupling
  • Event model solution, simple and easy-to-understand VB. NET version
  • Delegation
  • C # implementation
  • Move closer to the ". NET Framework Class Library Design Guide" for standard implementation

Concepts of events and event handlers

In object-oriented theory, an object (an instance of a class) can have properties, get or set the object state, and methods (actions that an object can do) and other members.Event(Event). An event is a notification sent to the outside world when the internal status of the object changes or when the object performs some actions (or before or after the action. For example, Zhang San suffered a stomachache. Then he stood in the open space and shouted, "My stomach hurts !" The event is the notification.

In this case, the external environment may have to respond to some events as compared with the Event Notifications sent inside the object. Next, for example, after James shouted, the ambulance arrived and took it to the hospital (or crazy people's hospital, haha, joke ). The external response to the event (specifically to the program, is the code written for the event), calledEvent Handler(Event Handler).

The event handler can be executed only after being linked to the event of the object. Otherwise, isolated event handlers are not executed. On the other hand, when an object event occurs, it does not have to have a corresponding processing procedure. Just as after James shouted, the external environment did not respond. That is to say, there is no inevitable connection between the event of the object and the event processing of the object. You need to hook it up.

Before learning, I hope that you will first distinguish the concepts of "events" and "event processing programs. Events are subordinate to objects (classes), and event handlers are responses of external code to events of objects. Events should be completed by the designers and developers of objects (classes); Event Handlers must be completed by external callers. Simply put, an event is "internal" and an event handler is "external ".

After learning about the above basic concepts, we start to learn the specific code implementation process. Because there are many codes involved and limited space, I just paste the important parts of the Code into the article for parsing. For the remaining code, please read it by yourself, I have packaged the source code for download. I also suggest you compare the source code to learn the tutorial. [Download the source code of this tutorial]

[Top]

 

Problem description: a task that takes a long time to complete

Demo 1A, Problem Description. This is a scenario demonstration. It is also a "actual problem" that other demos in this tutorial are dedicated to solving: dolongtimetask is a method that may take a long time to complete in the worker class:

Using system; using system. Threading; namespace percyboy. eventmodeldemo. demo1a {// worker that takes a long time to complete the task, without any reporting channel. Public class worker {// set the max value based on your machine configuration. // Here (CPU: AMD sempron 2400 +, ddram 512 MB) // when max = 10000, the task takes 20 seconds. Private const int max = 10000; public worker () {} public void dolongtimetask () {int I; bool T = false; for (I = 0; I <= max; I ++) {// here thread. sleep has two purposes: // One is to prevent all CPU time from being spent on this task: // because the work in this example is a task that consumes pure CPU computing resources. // If you keep using the CPU, almost all the CPU time is consumed. // If the task time is short, it may not affect much; // However, if the task time is long, it may affect the normal operation of other tasks in the system. // Therefore, sleep is to give the cpu a Chance To "split your mind" and // process the computing requests from other tasks. //// Of course, the main purpose here is to make this task seem to take longer. Thread. Sleep (1); t =! T ;}}}}

The interface is very simple (other demos in this tutorial also follow this interface, because our main research object is worker. CS ):

Click the start button to start executing this method. (The specific machine configuration conditions take different time to complete this task. You can adjust the max value in the Code according to your actual situation .)

If there is no progress indicator, the interface will not respond for a long time and is often considered a program fault or "dead" by the user. In fact, your work is not over yet. This tutorial provides an example to illustrate the principles, design, and code implementation of the event model in. net.

[Top]

 

High Coupling

Demo 1B, highly coupled. There are many ways for worker to report progress to the user interface at work, for example, the easiest way to think:

Public void dolongtimetask () {int I; bool T = false; for (I = 0; I <= max; I ++) {thread. Sleep (1); t =! T; write the code to refresh the status bar of the user interface here }}

If dolongtimetask is a method of the user interface (Windows form), the blue part above may be very simple, but it may be just the following two lines of code:

Double rate = (double) I/(double) max; this. statusbar. Text = string. Format (@ "completed {0: P2}...", rate );

In this case, dolongtimetask is part of the Windows form. Obviously, it is not conducive to other forms to call this code. So: The worker class should exist as a relatively independent part. This example is provided in source code demo1b (there should be many methods similar to it ):

In Windows form form1, click the start button to initialize a new instance of the worker class and execute its dolongtimetask method. However, you should also see that form1 also assigns an attribute to the worker. When the worker executes the dolongtimetask method, the status bar of form1 is refreshed through this attribute. Form1 and worker are mutually attached: form1 depends on the worker class (because it needs to instantiate worker after clicking the button), and the worker class also depends on form1 (because it is at work, to access form1 ). The two are highly coupled.

High coupling is also not conducive to code reuse. You still cannot use the worker class in another form, and the code flexibility is greatly reduced. The correct design principle should be to achieve low coupling: If form1 must depend on the worker class, the worker class should not depend on form1 in turn.

 

Next we will consider using the. NET event model to solve the above "high coupling" problem:

Let the worker class send a "Progress Report" Event Notification to the outside world during work (Ratereport). At the same time, to demonstrate more scenarios, let the worker class issue a "I'm getting started!" before starting dolongtimetask! There are n tasks in total ." Event Notification (Startwork), And send the "task completed" Event Notification when the task is completed (Endwork).

After the event model is used, the worker itself does not actually refresh the status bar of form1, that is, the worker does not rely on form1. In form1, click the "Start" button to start a worker instance and send a series of Event Notifications. What we need to do is to write Event Handlers for worker events and hook them up.

[Top]

 

Event model solution, simple and easy-to-understand VB. NET version

Demo 1C, VB. NET code. Although this tutorial uses C # As the example language, I still provide a piece of VB. NET code to help you understand it. I personally think that the event Syntax of VB. NET allows you to intuitively understand the "Way of Thinking" of the. NET event model ":

Public class worker private const max = 10000 public sub new () end sub 'Note: This example is incorrectly written. in the. NET Framework Class Library Design Guide, 'is simplified to help you quickly understand the event model. 'Continue reading. Use the VB. NET standard format of demo 1f. ''Indicates the number of work start events that need to be completed by the outside world. Public event startwork (byval totalunits as integer) 'Progress report event, notifying the progress of external tasks. Public event ratereport (byval rate as double) 'end of work event. Public event endwork () Public sub dolongtimetask () dim I as integer dim t as Boolean = false dim rate as double 'sends an event to the outside world to notify raiseevent startwork (max) for I = 0 to Max thread. sleep (1) t = not t rate = I/MAX raiseevent ratereport (rate) Next raiseevent endwork () end sub

First, the declaration part of the event: you only need to write the public event keyword, then write the event name, and then write the parameter declaration that needs to be sent to the outside world.

Then pay attention to the raiseevent keyword marked as blue. VB. NET uses this keyword to trigger an event within the class, that is, to send event notifications to the outside world. Pay attention to its syntax. After raiseevent is connected to the event name you want to raise, it is then the specific event parameter value.

In this example, we can deepen our understanding of the event model: an event is a member of an object (class) the internal status has some changes (for example, the rate is changing in this example), or when the object performs some actions (for example, in this example, when the method starts, it is directed to the external raise event; when the method ends, notifications sent to external raise events) and objects (classes. Also, you have learned how to use event parameters: the event parameters are related to Event Notifications. For example, ratereport Event Notifications need to report the progress value rate, and startwork Event Notifications need to report the total number of tasks Max.

I think raiseevent clearly illustrates these principles.

[Top]

 

Delegation introduction.

Before learning how to implement C #, we should first understand some basic concepts about "delegation.

You can simply think of "delegate" as. Net's function packaging (this is the main purpose of Delegate ). A delegate represents a "class" function, which meets certain specifications, such as having the same number of parameters, parameter type, and return value type. It can also be considered that delegation is the abstraction of functions and the "class" of functions (classes are the abstraction of things with some identical features ). In this case, the delegated instance represents a specific function.

You can use the following methodDelegate Declaration:

        public delegate void MyDelegate(int integerParameter);

The preceding delegate can be used to represent a group of functions with only one integer parameter and without return values. The method is similar to the method of writing a function. It only adds the delegate keyword but does not have the function body. (Note: In this article, functions are used in the process-oriented theory. In fully object-oriented. Net/C #, I want to refer to the instance method or static method of the class. By the way, since it is completely object-oriented, the delegate itself is also an object .)

Delegation instantiation: Since the delegate is the "class" of the function, it must be instantiated before using the delegate. Let's take a look at the following code:

    public class Sample    {        public void DoSomething(int mode)        {            Console.WriteLine("test function.");        }        public static void Hello(int world)        {            Console.WriteLine("hello, world!");        }    }

We can see that the sample instance method dosomething and static method Hello both comply with the "specifications" of the mydelegate delegate defined above ". We can use the mydelegate delegate to wrap them for special purposes (for example, the event model to be discussed below or the multi-threaded model to be discussed in future tutorials ). Of course, the packaging process is actually the instantiation process of delegation:

    Sample sp = new Sample();    MyDelegate del = new MyDelegate(sp.DoSomething);

This is the packaging of the above instance method. However, if this code is written inside the sample class, you should use this. dosomething instead of creating a new sample instance. The Hello static method of sample can be packaged as follows:

    MyDelegate del = new MyDelegate(Sample.Hello);

Call delegate: For a delegated instance (actually a specific function), if you want to execute it:

        del(12345);

Directly write the name of the delegated instance and assign values to the corresponding parameters in brackets. (If a function has a return value, it can also receive the return value as a normal function ).

[Top]

 

C # implementation

Demo 1d, C # implementation. Here is the C # Implementation of VB. NET code in demo 1c: Is it more complicated than VB. NET code?

Using system; using system. Threading; namespace percyboy. eventmodeldemo. demo1d {// worker that takes a long time to complete the task. This time, we use the event to notify the outside world of the progress. Public class worker {private const int max = 10000; // Note: This example is incorrectly written. the conventions in the. NET Framework Class Library Design Guide are simplified to help you quickly understand the event model. // Continue reading. Use the C # standard format of demo 1E/demo 1 h. // Public Delegate void startworkeventhandler (INT totalunits); Public Delegate void Merge (double rate); public event startworkeventhandler startwork; public event endworkeventhandler endwork; public event ratereporteventhandler ratereport; public worker () {} public void dolongtimetask () {int I; bool T = false; double rate; If (startwor K! = NULL) {startwork (max) ;}for (I = 0; I <= max; I ++) {thread. Sleep (1); t =! T; rate = (double) I/(double) max; If (ratereport! = NULL) {ratereport (rate) ;}} if (endwork! = NULL) {endwork ();}}}}

This code is consistent with the preceding VB. NET code. Through the C # code, we can see some implementation details hidden by VB. NET:

First, several delegates are declared at the beginning ). Then three events are declared. Here, note the C # method of event declaration:

Public event [Delegate type] [event name];

Here you can see that VB. NET hides the steps for declaring delegation.

In addition, you are reminded to pay attention to the specific part of the code that triggers the event:

        if (RateReport != null)        {            RateReport(rate);        }

Before calling a delegate, you must check whether the delegate is null. Otherwise, nullreferenceexception may occur. Compared with VB. net code, VB. net's raiseevent statement actually hides this details.

Now, the first version of the worker class sends event notifications to the outside world through the event model. Modify your windows form, add the ratereport event handler to it (see the source code you have downloaded) and link it together to see the effect:

After the progress indicator is added, the user experience is greatly improved and the user experience is more friendly.

[Top]

 

Move closer to the ". NET Framework Class Library Design Guide" for standard implementation

Demo 1E, C # standard implementation. The above has repeatedly stressed demo 1C, And the demo 1D Code does not comply with the CLS conventions. Microsoft provides some guidelines for the design and naming of. Net class libraries. As a convention,. NET developers should abide by these conventions. For more information about events, see the event naming Guide (corresponding online webpage) and event User Guide (corresponding online webpage ).

using System;using System.Threading;namespace percyboy.EventModelDemo.Demo1E{    public class Worker    {        private const int MAX = 10000;        public class StartWorkEventArgs : EventArgs        {            private int totalUnits;            public int TotalUnits            {                get { return totalUnits; }            }            public StartWorkEventArgs(int totalUnits)            {                this.totalUnits = totalUnits;            }        }        public class RateReportEventArgs : EventArgs        {            private double rate;            public double Rate            {                get { return rate; }            }            public RateReportEventArgs(double rate)            {                this.rate = rate;            }        }        public delegate void StartWorkEventHandler(object sender, StartWorkEventArgs e);        public delegate void RateReportEventHandler(object sender, RateReportEventArgs e);        public event StartWorkEventHandler StartWork;        public event EventHandler EndWork;        public event RateReportEventHandler RateReport;        protected virtual void OnStartWork( StartWorkEventArgs e )        {            if (StartWork != null)            {                StartWork(this, e);            }        }        protected virtual void OnEndWork( EventArgs e )        {            if (EndWork != null)            {                EndWork(this, e);            }        }        protected virtual void OnRateReport( RateReportEventArgs e )        {            if (RateReport != null)            {                RateReport(this, e);            }        }        public Worker()        {        }        public void DoLongTimeTask()        {            int i;            bool t = false;            double rate;            OnStartWork(new StartWorkEventArgs(MAX) );            for (i = 0; i <= MAX; i++)            {                Thread.Sleep(1);                t = !t;                rate = (double)i / (double)MAX;                OnRateReport( new RateReportEventArgs(rate) );            }            OnEndWork( EventArgs.Empty );        }    }}

Follow the conventions in the. NET Framework Class Library Design Guide:

(1) The event Delegate name should end with eventhandler;

(2) The "type" of the event Delegate should be two parameters: the first parameter is the object-type sender, which represents the object that sends the Event Notification (this keyword is generally used in the Code (VB. net )). The second parameter E should be of the eventargs type or the type inherited from eventargs;

Event parameter type, which should inherit from eventargs and end with eventargs. Put all the information that you want to send to the outside world through the event in the event parameter E.

(3) generally, as long as the class is not sealed (sealed, VB. net), or this class can be inherited, should provide a protected for each event and can be rewritten (C # With Virtual, VB. net overridable) onxxxx method: This method name should be on with the event name; there is only one event parameter E; generally, this method performs null judgment, in addition, this/me is used as the sender to execute the event Delegate. This onxxxx method should be called where Event Notifications need to be issued.

If you want to change the behavior when this event occurs, rewrite the onxxxx method, generally, this method of the base class should be called (base in C. onxxxx, VB. net with mybase. onxxxx ).

I suggest you continue to spend some time studying the code writing. It is the standard event implementation code of C #. I believe you will need it!

In Demo 1d, I didn't explain how to hook the event handler to the Event code of the worker instance. In this demo, I listed the main parts here:

Private void button#click (Object sender, system. eventargs e) {statusbar1.text = "Getting started .... "; this. cursor = cursors. waitcursor; long tick = datetime. now. ticks; worker = new worker (); // hook the event handler with the corresponding event of the worker // here I only hook the ratereport event to indicate worker. ratereport + = new worker. ratereporteventhandler (this. worker_ratereport); worker. dolongtimetask (); tick = datetime. now. ticks-tick; timespan Ts = ne W timespan (tick); this. cursor = cursors. Default; statusbar1.text = string. Format ("task completed, time consumed {0} seconds. ", Ts. totalseconds);} private void worker_ratereport (Object sender, worker. ratereporteventargs e) {This. statusbar1.text = string. format ("completed {0: P0 }.... ", E. rate );}

Note the mounting method of C # ("+ =" operator ).

Here, you have seen the advantages of the event mechanism: the worker class code has no dependency with this Windows form. Worker classes can exist independently and can be repeatedly applied to different places.

For VB. NET readers, please refer to the VB. Net standard event writing method in demo 1f and refer to the instructions here. I will not go into details here.

Reference from: http://www.iwms.net/n1357c13.aspx

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.