Personal C Sharp                                                         By  famsoft.org
Home How To Start Examples-Desktop Examples-Web PC# Methods Reference-Desktop Reference-Web


DEMONSTRATIVE EXAMPLES ====================== If you intend to practice with the coming examples, you need to learn about domains and web applications first. To do so, click on "How to Start" then on "Startup, Web Applications". WEB PAGE DEVELOPMENT I ====================== HTML ELIMINATION: The asp.net has added a great enhancement to web development by allowing you to do a major part of your web development programmatically. The asp.net page files which use the extension (.aspx) are not sent by the server to the client's browser directly. They actually run at the server where an HTML file is generated and sent to the browser instead. Unfortunately, html has not been eliminated entirely. The asp.net web files are required to contain html tags even if the page was entirely developed using asp.net code. In order to simplify things further while maintaining all the added enhancement and power, we have developed a software which allows you to write your entire web page file in C# with absolutely no html. When you add all the simplicity of using PC#'s tools and methods to the elimination of HTML, you come up with the easiest and most pleasant web development ever. HOW DOES IT WORK? Here is how it is done: (1) You write a code file (.cs) as usual which extends class (pasp) In that file, you supply PC# software with every control which you like to include into the web page and where you like it to be using the same simple methods which you have been using to set windows Form controls. The controls are set into table cells. Then the tables are set into the cells of larger tables. This Continues until we end with one large table of the same size as the page (the root table). We use the keyname "tb0" for the root table which contains the entire page data. (2) Now it is time for the (.aspx) file which the browser requires. We need a file which extends (inherits) the code file above and contains in its html section only one control which is the root table. So the (.aspx) files for all pages are the same. The only difference between one file and another is in the name of the code file it extends. This makes creating the (.aspx) file a repeated job which you need not to do. You create the code file only then use the tool (pcw) to generate the (.aspx) file for you. EXAMPLE A: In this example we are going to develop a web page which contains the table heirarchy necessary for the following several examples. As you can see the page contains 5 empty tables. The top table will contain the page title, an icon and the pages' index. The second and third tables will be used to show two new features in each example. The fourth and fifth tables will display data coming back from the server in response to events generated by the user at tables 2 and 3 respectively. ========================================================================================= public partial class a:pasp { // Since class name is (a), it must // be saved into a file named a.cs public override void init() { // This is the usual init() method base.init(); // Initialize pasp class. } public override void setup() { // This is the usual setup method //---------------------------------- Page Contents ----------------------------------- cns=""; // tb0 has no container since it is // mounted directly on the page. cs="tb0";cls="S9g8";fns="trb12";wm("i"); // tb0's installation parameters //---------------------------------- tb0's Contents ---------------------------------- cns="tb0"; // Container=tb0 for next 5 tables cs="tb1";j=0;k=0;i=2;lf=760;of=100;cls="S9p7";fns="trb12";jd=5;ds="n";wm("i"); cs="tb2";j=0;k=1;lf=380;of=250;cls="S9p7";fns="trb12";jd=5;wm("i"); cs="tb3";j=1;k=1;lf=380;of=250;cls="S9p7";fns="trb12";jd=5;wm("i"); cs="tb4";j=0;k=2;lf=380;of=50;cls="S9p7";fns="trb12";jd=5;wm("i"); cs="tb5";j=1;k=2;lf=380;of=50;cls="S9p7";fns="trb12";jd=5;wm("i"); // Tables will not show up unless they contain something. So, we'll install a literal // control into each table containing it's keyname. //---------------------------------- tb1's Contents ----------------------------------- cns="tb1"; // tb1 contains next control(s) cs="lt1";cis="tb1";wm("i"); // Literal control containing text //---------------------------------- tb2's Contents ----------------------------------- cns="tb2"; cs="lt2";cis="tb2";wm("i"); //---------------------------------- tb3's Contents ----------------------------------- cns="tb3"; cs="lt3";cis="tb3";wm("i"); //---------------------------------- tb4's Contents ----------------------------------- cns="tb4"; cs="lt4";cis="tb4";wm("i"); //---------------------------------- tb5's Contents ----------------------------------- cns="tb5"; cs="lt5";cis="tb5";wm("i"); } public override void update() { setup(); // Execute method setup() MakePage(table); // Make the page with tb0 containing } // all its contents. } ========================================================================================= HOW TO WRITE THE PROGRAM? Use NotePad. Since "a" has been chosen to be the name of the class, save the program into a file named "a.cs". HOW TO GENERATE THE WEB (.aspx) FILE? From Command mode, type: 'pcw a' and hit [ENTER]. This should generate the file "a.aspx". HOW TO RUN THE PROGRAM? Type the page's address into your browser's address line and hit [ENTER]. You may do that locally or using a computer anywhere accross the web. The page address is in the form: DomainAddress/ApplicationFolder/AspxFile As explained thoroughly in "How to start - Web applications", if you are testing your program locally, you may type into the address bar: http://localhost/AppFolder/a.aspx or http://169.254.100.123/AppFolder/a.aspx depending on your setup. Note that the 4 digits are used as an example only. The actual ones for your system could be different. If you are accessing your program from another computer, you may need to type: http://www.domain.com/AppFolder/a.aspx ========================================================================================= TUTORIAL: --------- (1) Your class extends class "pasp". Class "pasp" extends class "System.Web.UI.Page" which allows it to access all nesessary asp.net software for the page in addition to allowing you to use mostly all the PC# methods which simplify your programming tasks. (2) One method which you cannot find in class (pasp) is method cm(). Method cm() which is included into class (pcs) helps you in developing controls which are mounted on window forms. This method has been replaced with method wm() which is very similar in its operation to method cm() except that it helps you in developing web controls. (3) Method setup() works the same as it used to do with window forms with few exceptions: a) It does not run automatically when your class is initialized. It stays unused until Your program calls it from method update() when a specific event takes place. b) Controls are not placed using absolute positioning. They are placed into table cells. So (j,k) no longer mean the position of a control in pixels, they now mean the order of the starting column and row which the control occupies within its containing table. Similarly, (i,o) mean the number of columns and rows occupied by the control instead of (width,height) in pixels. c) Finally, each control is set by calling method wm("i") instead of calling cm("i"). (4) Method update() is called each time an event takes place. Whenever a control is activated, method update is called with the keyname of the activated control assigned to (cs). However, not all events are caused by a control being activated. The first event which method update is called for, is the "Page Load" event. It is generated when the page is ready to load. The keyname variable (cs) is assigned the value "pl" before method update() is called. However, we did not check this value in this example since this is the only event which is expected to be received. When method update() was told that the page is ready to load, it called method setup() to read control parameters then it called method MakePage() to load all controls and their table containers into the root table "tb0", then load "tb0" into the table container which is declared in the ".aspx" file. INSTALLING CONTROLS INTO THEIR CONTAINERS: All the controls of this example are of type (Table). We want to install tables (tb1:tb5) into a specific locations in table (tb0) It may sound like a very easy task, but in many cases it is not. What makes this job not too easy is the conflict between two intelligent entities, you and the browser. You assume that you know what you are doing and expect the browser to set the table columns and rows exactly the way you want them to be. The browser assumes that you may not be understanding what you are doing so it should do things for you in order to improve the look of your table. Here is what the browser tries to do: (1) If you set the size of your table in pixels, it tries to respect your setting as long as the size is equal or more than the size which table contents require. If not, it neglects your setting and sizes the table as it sees necessary. (2) It does not make all columns of the table equal in width or all rows equal in height. It checks to see the widest object installed into the column (anywhere in the table) and makes the column wide enough to contain that object. It applies the same logic when it sets row sizes too. (3) It does not display an empty table even if you specify its width and height in pixels. And here is what you can do to get around this problem: (1) Always apply the simplest logic possible in setting your controls. (2) If you get an unexpected layout of your controls do the following: a) Make the container table grids show by adding (ib=true) to the table's setup parameters. This should give you a clearer picture of what is happening. b) Locate the widest control in each column and the tallest control in each row. They are the keys to fixing the problem. Readjusting their sizes can change the entire layout of the table. Sizes of most controls can be changed by changing the font size of the text they contain. Now let us return to the example. Here is how you can determine the number of rows and columns for tb0: (1) Locate the row which contains the largest number of controls horizontally. The number of columns necessary is equal to the number of controls at that row which is 2. (2) Locate the column which contains the largest number of controls vertically. The number of rows necessary is equal to the number of controls at that column which is 3. Here are some comments on the setup data: (1) For the root table (tb0) we did not set values for (j,k,i or o) since it is the root. However, these values are necessary for all other controls. (2) If the control should occupy one column we suould supply (i=1), however since this is the default we can just assign no value to (i) Method wm("i") changes (i=0) to (i=1) internally. Same logic applies to (o). (3) For (tb1): (j=0;k=0;i=2;) means that it occupies two columns and one row (since o is not assigned a value) and that the coordinates of the first table cell it occupies are (0,0). (4) For (tb2): (j=0;k=1;) Since (i,o) are not assigned values, it occupies one column and one row, The coordinates of the first table cell it occupies are (0,1). (5) For (tb3): (j=1;k=1;) Since (i,o) are not assigned values, it occupies one column and one row. The coordinates of the first table cell it occupies are (1,1). (6) We have assigned values to (lf,of) for all tables except the root. These values set the table sizes (horizontally, vertically) in pixels. Not specifying size for (tb0) causes no problem since as mentioned above, the browser will make it large enough to contain all the tables which have been installed into it. (7) Colors and fonts have been set as usual. (jd=5) means frame the table with a 5 pixels wide frame. It makes them look nice, however you can remove it if you don't like frames. (8) As you must know, after method wm("i") completes the installation of each control, it resets all parameters. The only exception to this rule is the container name (cns) This allows you to assign a value to (cns) one time only before installing a group of controls into a new container. =========================================================================================


EXAMPLE 1: Now, let us make our first web page. We need to do the following: (1) Create Application title and install it into the top container (tb1) (2) Install a business logo at the right side of (tb1) (3) Create a navigation index at the bottom of (tb1) which allows the user to browse through the website. (4) Remove the pink paint of (tb2) and tile it with the image "flower.jpg" instead. (5) Install a hyper link into (tb2) which the user can click on to order flowers. (6) Create a table and install it into (tb3). ========================================================================================= public partial class pg1:pasp { public override void init() { base.init(); } public override void setup() { //---------------------------------- Page Contents ----------------------------------- cns=""; // tb0 Container="" since it's // mounted directly on the page. cs="tb0";cls="S9g8";fns="trb12";wm("i"); // tb0 installation parameters //----------------------------------- tb0 Contents ----------------------------------- cns="tb0"; // Container=tb0 for next tables cs="tb1";j=0;k=0;i=2;lf=760;of=100;cls="S9p7";fns="trb12";jd=5;ds="n";wm("i"); cs="tb2";j=0;k=1;lf=380;of=250;ims="flower.jpg";fns="trb12";jd=5;wm("i"); cs="tb3";j=1;k=1;lf=380;of=250;cls="S9p7";fns="trb12";jd=5;wm("i"); cs="tb4";j=0;k=2;lf=380;of=50;cls="S9p7";fns="trb12";jd=5;wm("i"); cs="tb5";j=1;k=2;lf=380;of=50;cls="S9p7";fns="trb12";jd=5;wm("i"); // tb2 is tiled with image, all // others painted with lt pink color //----------------------------------- tb1 Contents ---------------------------------- cns="tb1"; // tb1 is divided into 4 col,3 rows wm("o"); // Open a new html loading operation cls="r0";fns="trb24";ds="c";os="Web Page Development";wm("dp"); wm("c"); // Insert Ap title into (cis) Create cs="lt1";j=0;k=0;i=3;ds="c";wm("i"); // Literal control,make cis its text cs="lt2";j=0;k=1;i=3;cis="Example Number One";ds="c";fns="trb12";wm("i"); // Create (lt2) containing Pg title cs="hl0";j=0;k=2;cis="Example Number One";fns="trb12";cls="s9b0";ds="c"; urs="http://www.microsoft.com";wm("i");// Create Hyper text control which // displays page 1 when clicked. cs="hl1";j=1;k=2;cis="Example Number Two";fns="trb12";cls="s9b0";ds="c"; urs="http://www.microsoft.com";wm("i");// Do same for page 2 cs="hl2";j=2;k=2;cis="Example Number Three";fns="trb12";cls="s9b0";ds="c"; urs="http://www.microsoft.com";wm("i");// Do same for page 3 cs="im0";j=3;k=0;i=1;o=3;ds="e";lf=190;of=90;ims="images\\icon.jpg";jd=5;wm("i"); // Image, scaled to (190,90) pixels //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 1 col, 1 row wm("o"); // Open a new html loading operation urs="http://www.microsoft.com";os="To order flowers, Click Here"; cls="y0";fns="trb16";wm("a");wm("c"); // Create hyper text link in (cis) cs="lt3";ds="n";wm("i"); // Create (lt3), make (cis) its txt //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 1 col, 1 row wm("o"); // Open a new html loading operation cls="G5";fns="trb14";ds="c";os="Flower Prices";wm("dl"); // Insert table's title into (cis) // in addition to all coming html: i=5;o=65;wm("to"); // open table,bordr=5, width=65% OS[0]="Collection";OS[1]="Price";wm("th"); // Make a 2 column header OS[0]="Mixed Tulips";OS[1]="$25.00";wm("td"); // and 3 data rows. All the html OS[0]="Color Roses";OS[1]="$30.00";wm("td"); // generated is inserted into (cis) OS[0]="Pink Lilies";OS[1]="$50.00";wm("td"); // wm("tc"); // Add closing table html tags and wm("c"); // closing tags for other html ones cs="lt4";wm("i"); // Create (lt4), make (cis) its txt //----------------------------------- tb4 Contents ---------------------------------- cns="tb4"; // tb4 is made of 1 col, 1 row cs="lb10";cis="Server Response: ";wm("i"); // Create (lb10), cis=its txt //----------------------------------- tb5 Contents ---------------------------------- cns="tb5"; // tb5 is made of 1 col, 1 row cs="lb11";cis="Server Response: ";wm("i"); // Create (lb11), cis=its txt } public override void update() { setup(); // Execute method setup() MakePage(table); // Make the page } // containing all controls } ========================================================================================= TO LEARN HOW TO WRITE THE PROGRAM, GENERATE THE (.aspx) FILE AND TO RUN IT, See Example A ========================================================================================= TUTORIAL: We expect you to study according to the recommended study sequence. This means that you should know how to install and use Windows Form controls. If you don't, please study them first. Installing web controls is similar to installing windows controls with few differences. The new features of the control label (cis): -------------------------------------------- In the case of windows controls, the control label is assigned to (cis) and its alignment within its control is assigned to (os) before calling method cm("i") to install a control The label is displayed in the same color and font which are assigned to the control. Only few controls can have labels installed this way. Here, we do the same except that the rule of (cis) has been expanded significantly. Here are some new features: (1) More controls now have labeles assigned in this manner. The "text field" for example can have one. (2) There is a new control called the "Literal control" which is nothing but (cis). If no value is assigned to (cis) for a Literal control, it becomes invisible since it has no body in this case. (3) The string assigned to (cis) does not have to be made of pure text, it can contain HTML code. This makes it capable of setting its own color, font and location, in addition to storing hyperlinks, tables, images,.. etc. You can store a whole page into (cis) then assign it to a Literal control to get it to show up. Loading (cis) with text/html: ----------------------------- As promised, you don't have to know HTML. Method wm() does all the job for you. This subject will be discussed in more details in future examples. For now, just know that you start by calling wm("o") to start the operation. Then you use wm("d"), wm("dl") and wm("dp") to display text. Also, you can use wm("a") to create hyper links and wm("to"), wm("th"), wm("td") and wm("tc") to create and populate tables. finally, you use method wm("c") to close the operation. All the text and HTML tags generated by those methods are concatenated into the string (cis). You follow that with creating a control which uses (cis) as its label in order to make the html show when the page is deployed. If you are anxious to know more about this subject quickly, see examples (7-9) of group "WPDII". REMARK: You may notice that in some examples when only a small amount of html is loaded into (cis), we neglect to use wm("o") and wm("c"). The purpose in using the two modes is insuring that any opening html tag loaded is matched with a closing one. Some may argue saying that this is not necessary since the ASP.NET does the same thing. We still advise you to include them to make sure things are in order. Let us now analyze the Literal Controls used in the example: (1) lt1: The top line of (lt1)'s setup was: cls="r0";fns="trb24";ds="c";os="Web Page Development";wm("dp"); We have called method wm() at mode "dp". This mode starts a new paragraph then displays the wanted text there. The wanted text is the text assigned to (os). We have also told the method to use pure red color, TimesRoman, bold, size 24 font and to display the text at the center. Method wm("dp") has generated several HTML tags to do all the text setup in addition to the text itself. All the HTML generated is concatenated together and added to (cis) If we then call the same method to display a new paragraph, the new HTML will also be concatenated to the current one into (cis) Then the second line came which was: cs="lt1";j=0;k=0;i=3;ds="c";wm("i"); This says create a Literal control which occupies all the 3 columns of (tb1) starting at cell(0,0) and centered into the 3 table cells. The string (cis) which has been loaded with html is this control's body. (2) lt2: The label for this one has been a simple short text so its setup was made in one line (3) lt3: Here is the setup section for this Literal control: wm("o"); // Open a new html loading operation urs="http://www.microsoft.com";os="To order flowers, Click Here"; cls="y0";fns="trb16";wm("a");wm("c"); // Create hyper text link in (cis) cs="lt3";ds="n";wm("i"); // Create (lt3), make (cis) its txt The top three lines have created (cis). Method wm("a") was used to generate the HTML "anchor" tag which makes the Hyperlink. Method wm("a") requires the clickable text assigned to (os) and the "URL", assigned to (urs) That was done at the top line. The color and font to display the clickable text with have been also supplied. All generated HTML have been loaded into (cis) automatically by method wm("a"). The fourth line has created the Literal control stating that it should be placed at the top (north) of its cell. (4) lt4: This literal control has required a complex label. The first section of the label was the table's title which has been created using the code: cls="G5";fns="trb14";ds="c";os="Flower Prices";wm("dl"); Every thing here is similsr to the code used for (lt1) except that we did not want to write the title at a new paragraph, we wanted to display it directly then move to next line instead, so we used method wm("dl") Next to that, we wanted to add to (cis) the HTML necessary to create a table. Here is how it was done: i=5;o=65;wm("to"); // open table,bordr=5, width=65% OS[0]="Collection";OS[1]="Price";wm("th"); // Make a 2 column header OS[0]="Mixed Tulips";OS[1]="$25.00";wm("td"); // and 3 data rows. All the html OS[0]="Color Roses";OS[1]="$30.00";wm("td"); // generated is inserted into (cis) OS[0]="Pink Lilies";OS[1]="$50.00";wm("td"); // wm("tc"); // Add closing table html tags and wm("c"); // closing tags for other html ones The first step is calling wm("to") to generate necessary tags for a table with border width of 5 pixels and a total width of 65% of its container's width. Next step is to write the table header. All column titles are assigned to OS[] before calling wm("th"). Next is to enter all data rows in the same manner. The last step in creating a table is to close it using method wm("tc") to generate closing tags for all open table tags. As a precaution, we called wm("c") which checks to see if the generated HTML contains an HTML tag of any type without its matching closing one. If any was found, it adds the necessary closing tag. HYPERLINK CONTROLS: The Hyperlink control functions the same as the hyperlinks generated by the Literal control except that it puts the clickable text into a box which makes it more suitable for making an index to navigate a site with. It can also be turned into a clickable image if you supply the image's URL assigned to (ims). IMAGE CONTROLS: This control makes it easy to place an image at any location you choose in the page. The image's URL is supplied to (ims). You can scale the image to any size you want if you assign the wanted (width,height) to (lf,of) respectively. LABEL CONTROLS: They display text similarly to Literal controls except that the text is inserted into a box. MORE ABOUT (cis): A Literal control is not the only control which uses (cis) as its label. There are many other controls which do the same. Fortunately you can use the HTML generating modes of method wm() to display them using any color, font or indention just like you do with literal controls. =========================================================================================


MASTER PAGES ============ The ASP.NET 2.0 includes several new features like master pages, custom controls and web parts which enhance web development. PC# must do her best to implement as many useful features as possible, however PC# must never go beyond what it is for which are: (1) Making programming as easy and simple as possible. (2) Performing tasks with the shortest possible code. (3) Things to memorize must be reduced to minimum. Making you able to write the most powerful web page program possible while abiding with the rules above requires some careful decision making. The web page design is modular. This is accomplished by using table containers for each section. This by itself makes each section a reusable web part without additional programming complexity. Normally most pages of a website contain common sections like a header, a navigation index and/or a footer. The page you have created in the previous example shows that clearly. The top table (tb1) with everything it contains is going to be common for all the pages which we are going to develop. Tables tb4 and tb5 are also common. Including these common parts into every page class we write is a waste of time and resources. The better choice is to create a master page class which includes the common parts alone and make it execute together with each page class. In order to create a master page, your class must extend class "System.Web.UI.MasterPage" instead of class "Page" (Your class extends class "Page" when it extends "pasp") The master page file extension should be ".master" instead of ".aspx". Also the ".aspx" files for the content pages which are generated for you by the tool "pcw" will need to be modified. In order to avoid the master page creation complexity, we use a simpler way to do the same job. Our master page code file is the same as any page code file. Instead of using tool "pcw" to generate the matching ".aspx" file, we use tool "pcwm" which compiles the master page code file and saves the resulting ".dll" file into the "Bin" subdirectory. The master page class extends class "pasp" which extends "Page". All your page classes will extend the master class. This means that you have the following class hierarchy: Page ---> Class pasp ---> Your Master Page Class ---> Your page classes Both "pasp" and the master page classes are stored into the "Bin" subdirectory of your application's directory in the form of ".dll" files. Your page classes are kept into your application directory in the form of ".cs" files. You may have more than one master class although this is not recommended. If you do, you must make them extend one another. The deepest of them should extend class (pasp) and the top one should be extended by the page classes. Now we are going to split the class of example 1 into two classes. The first class will be named "master1" and will include the creation of all the table containers and the population of tables tb1,tb4 and tb5. The second class will keep the name "pg1" and will include the population of tables tb2 and tb3 only in addition to method update() which handles all events of the page. Class "master1" will be expanded to include hyperlinks for 10 pages and will also include a method named PageNumber() which all page classes will be calling in order to make their page numbers show at the top of the page. Table (tb2)'s background will be painted the same as all other tables instead of being tiled with an image. Class "pg1" will populate (tb2) differently in order to maintain the same look despite that change. THE MASTER CLASS: ================= public partial class master1:pasp { // The master class must extend pasp // or a deeper master class public override void setup() { //---------------------------------- Page Contents ----------------------------------- cns=""; // tb0 Container="" since it's // mounted directly on the page. cs="tb0";cls="S9g8";fns="trb12";wm("i"); // tb0 installation parameters //----------------------------------- tb0 Contents ----------------------------------- cns="tb0"; // Container=tb0 for next tables cs="tb1";j=0;k=0;i=2;lf=760;of=100;cls="S9p7";fns="trb12";jd=5;ds="n";wm("i"); cs="tb2";j=0;k=1;lf=380;of=250;;cls="S9p7";fns="trb12";jd=5;wm("i"); cs="tb3";j=1;k=1;lf=380;of=250;cls="S9p7";fns="trb12";jd=5;wm("i"); cs="tb4";j=0;k=2;lf=380;of=50;cls="S9p7";fns="trb12";jd=5;wm("i"); cs="tb5";j=1;k=2;lf=380;of=50;cls="S9p7";fns="trb12";jd=5;wm("i"); //----------------------------------- tb1 Contents ---------------------------------- cns="tb1"; // tb1 is divided into 4 col,3 rows cls="r0";fns="trb24";ds="c";os="Web Page Development";wm("dp"); cs="lt01";j=0;k=0;i=10;ds="c";wm("i"); // Insert Ap title into (cis) Create // Literal control, make cs its text cs="lt02";j=0;k=1;i=10;cis="Insert Page's Number Here";ds="c";fns="trb12";wm("i"); // Create (lt02) containing Pg title cs="hl01";j=0;k=2;cis="Page 1";fns="trb12";cls="s9b0";ds="c";urs="pg1.aspx";wm("i"); cs="hl02";j=1;k=2;cis="Page 2";fns="trb12";cls="s9b0";ds="c";urs="pg2.aspx";wm("i"); cs="hl03";j=2;k=2;cis="Page 3";fns="trb12";cls="s9b0";ds="c";urs="pg3.aspx";wm("i"); cs="hl04";j=3;k=2;cis="Page 4";fns="trb12";cls="s9b0";ds="c";urs="pg4.aspx";wm("i"); cs="hl05";j=4;k=2;cis="Page 5";fns="trb12";cls="s9b0";ds="c";urs="pg5.aspx";wm("i"); cs="hl06";j=5;k=2;cis="Page 6";fns="trb12";cls="s9b0";ds="c";urs="pg6.aspx";wm("i"); cs="hl07";j=6;k=2;cis="Page 7";fns="trb12";cls="s9b0";ds="c";urs="pg7.aspx";wm("i"); cs="hl08";j=7;k=2;cis="Page 8";fns="trb12";cls="s9b0";ds="c";urs="pg8.aspx";wm("i"); cs="hl09";j=8;k=2;cis="Page 9";fns="trb12";cls="s9b0";ds="c";urs="pg9.aspx";wm("i"); cs="hl10";j=9;k=2;cis="Page 10";fns="trb12";cls="s9b0";ds="c";urs="pg10.aspx";wm("i"); cs="im00";j=6;k=0;o=3;ds="e";lf=190;of=90;ims="images\\icon.jpg";jd=5;wm("i"); // Image, scaled to (190,90) pixels //----------------------------------- tb4 Contents ---------------------------------- cns="tb4"; // tb4 is made of 1 col, 1 row cs="lb00";cis="Server Response: ";wm("i"); // Create (lb00), cis=its txt //----------------------------------- tb5 Contents ---------------------------------- cns="tb5"; // tb5 is made of 1 col, 1 row cs="lb01";cis="Server Response: ";wm("i"); // Create (lb01), cis=its txt } public void PageNumber(int pgno) { // Page number insertion method cs="lt02";cis="Page Number "+pgno;wm("sl"); // Set the label of (lt02) to display } // the page number supplied. } ========================================================================================= Save this class into a file named "master1.cs" Then, from Command Mode, type: pcwm master1 [ENTER] ========================================================================================= THE PAGE CLASS: =============== public partial class pg1:master1 { // All page classes must extend the // top of the master class hierarchy public override void init() { base.init(); } public override void setup() { base.setup(); // Run setup() of master page first //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 1 col, 1 row urs="http://www.famsoft.org";os="To order flowers, Click Here"; cls="S9";fns="trb16";wm("a");wm("c"); // Create hyper text link in (cis) cs="lt3";j=0;k=0;i=2;ds="n";wm("i"); // Create (lt3), make (cis) its txt cs="im2";j=0;k=1;ds="se";lf=180;of=200;ims="..\\images\\flower.jpg";wm("i"); cs="im3";j=1;k=1;ds="sw";lf=180;of=200;ims="..\\images\\flower.jpg";wm("i"); //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 1 col, 1 row cls="G5";fns="trb14";ds="c";os="Flower Prices";wm("dl"); // Insert table's title into (cis) // in addition to all coming html: i=5;o=65;wm("to"); // open table,bordr=5, width=65% OS[0]="Collection";OS[1]="Price";wm("th"); // Make a 2 column header OS[0]="Mixed Tulips";OS[1]="$25.00";wm("td"); // and 3 data rows. All the html OS[0]="Color Roses";OS[1]="$30.00";wm("td"); // generated is inserted into (cis) OS[0]="Pink Lilies";OS[1]="$50.00";wm("td"); // wm("tc"); // Add closing table html tags and wm("c"); // closing tags for other html ones cs="lt4";wm("i"); // Create (lt4), make (cis) its txt } public override void update() { setup(); // Execute setup() MakePage(table); // Make the page PageNumber(1); // Call master1 class's method to } // set page number } ========================================================================================= Create the ".aspx" file with the command pcw pg1 and execute the page pg1.aspx file exactly as you have been doing before. =========================================================================================


INTERACTING WITH USERS ====================== Interacting with user is done almost identically as it is done with window forms. PC# receives all events then calls the update method of your class supplying it with the keyname of the control where the event has occured assigned to (cs). The first event received is the "Page_Load" event which occures when the page is ready to be retrieved. Although this event is not generated by a control, PC# makes it identifiable by assigning "pl" to (cs) before calling method update() when this event is received. When the user clicks a button, PC# receives this event, checks the button's identity and assigns the button's keyname to (cs) then calls method update() of your class. In method update(), you can get the latest update for any control by calling wm ("gu") This allows you to know everthing the user has selected in the page. After analyzing user selsections, you may like to send him/her a message back. You can do so by assigning the message to the label (cis) of the Literal or Label control which the user expects to receive your response at, then call method wm("sl") to update the control with the new label. Example 2: In table 2, we are going to demonstrate how to receive the text which the user has entered into a text field and send back a confirmation to the user. In table 3, we are going to demonstrate how to create a clickable image. ========================================================================================= public partial class pg2:master1 { // Page class extends master class public override void init() { base.init(); } public override void setup() { base.setup(); // Run setup() of master page first //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 1 col, 2 rows cs="tf0";cis="Enter Your Name";j=0;k=0;ds="c"; // tf0 is centered into 1st row jf=20;cls="b0y0";fns="trbi12";wm("i"); // tf0 size is 20 chars. cs="bt0";cis="Submit";j=0;k=1;ds="c"; // bt0 is centered into 2nd row cls="r0g8";fns="trb12";wm("i"); // Its label is "Submit" //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 1 col, 1 row cs="hl3";ds="c";ims="..\\images\\pix.jpg";jd=5; // Clickable image cis="Click Here";urs="http://www.famsoft.org";cls="b0s9";wm("i"); } //------------------------------------------------------------------------------------ public override void update() { if(cs.Equals("pl")) { // If event is "Page_Load" setup(); // Execute setup() MakePage(table); // and Make the page PageNumber(2); // Calling master class's method } // to display this page's number if(cs.Equals("bt0")) { // If event is: "bt0 clicked" cs="tf0";wm("gu"); // Get update text of tf0 in (cus) cs="lb00";cis="You entered: "+cus;wm("sl"); // Modify lb00's text with server } // response. } } =========================================================================================


USING VARIABLES IN WEB PAGE DEVELOPMENT ======================================= All the variables which you declare in your web page class or PC# declares for you are good for one trip only. This means that you can use them to prepare the page before it is sent to the user, but after the user clicks a button and you like to work on the page again, you cannot expect that your variables have retained their values. However, ASP.NET allows us to declare variables which retain their values. Here are the types of variables which retain their values: (1) Page Variables: Page variables retain their values over one page use only. This means that if the user changes page, the variable values are lost. (2) Session Variables: Session variables retain their values over one Session. This means that if the user changes page, the variables keep their values as long as the session has not been terminated. If the user stays inactive for 20 minutes, the session terminates and the variables are lost. The 20 minute limit is a default which can be changed. (3) Application Variables: This is the most durable type (and also the costiest). They keep their values as long as the application is running and this requires at least one user to request any page of the application. PC# Simplification: ------------------- All variables PC# can store and read back for you must be of string type. You can convert a string to and from any other type using method om(). The name of a page variable must end with "_p". The name of a session variable must end with "_s". The name of an application variable must end with "_a". Method wm("vs") sets (meaning assigns a value to) a variable. Method wm("vg") gets (meaning retrieves the value of) a variable. Parameters used with the methods: ks=variable name os= its value Examples: (1) To store the string "Apple" into the page variable (Fruit_p): ks="Fruit_p";os="Apple";wm("vs"); (2) To Get the value of the Session variable (Fruit_s): ks="Fruit_s";wm("vg"); // The obtained value will come assigned to (os) (3) To store the string "Orange" into the application variable (Fruit_a): Application.Lock(); // Lock application to keep other pages out temporarily ks="Fruit_a";os="Orange";wm("vs"); Application.UnLock(); // Unlock the application Look at example 3 carefully. We need to lock the application before modifying an application variable in order to avoid data corruption. This practice is commonly used with threads. We are not going to do the locking in the next example since we expect you to be the only user. If you try to get a variable which has not been stored or its place has been corrupted, you should end with an exception. However method wm() does its best to prevent this from happening. So, most likely, you'll end with getting the value (os="") instead. Example 3: LEFT SECTION: Install a calendar control. Get the date the user has selected and display it. RIGHT SECTION: Create 3 variables, an application var, a session var and a page var. Install a button control and increment all var's each time the button is clicked. ========================================================================================= public partial class pg3:master1 { public override void init() { base.init(); } public override void setup() { base.setup(); // Run setup() of master page first //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 1 col, 1 row cs="ca0";j=0;k=0;fns="trb8";ib=true;cls="r0g8"; // calendar control, show grid lines ds="c";lf=100;of=100;jd=5;kd=1;wm("i");// Borders=5 pxls, CellSpacing=1 pxl cs="bt0";cis="Submit";j=0;k=1;ds="c"; // button control fns="trb12";cls="r0g8";wm("i"); //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 1 col, 1 row cs="bt1";cis="Increment Counters";ds="c"; // button control fns="trb14";cls="b0y0";wm("i"); } //----------------------------------------------------------------------------------- public override void update() { //------------------------------------ Page Load ------------------------------------ if(cs.Equals("pl")) { // If event is "Page_Load" ks="c_a";wm("vg"); // test to see if variable is null ob=false;if(os.Length<1) ob=true; // Use ob as a flag of being null if(ob || !IsPostBack) { // If sample was found null for any ks="c_a";os="0";wm("vs"); // reason or if this was first page ks="c_s";os="0";wm("vs"); // retrieval, store"0" into all ks="c_p";os="0";wm("vs"); // 3 var's. } setup(); // Execute setup() MakePage(table); // and make page. PageNumber(3); // Calling master class's method } // to display this page's number //----------------------------------- Calendar Update ---------------------------------- if(cs.Equals("bt0")) { // If Calendar date selected cs="ca0";wm("gu"); // Get Calendar update (date in cus) cs="lb00";cis="You selected: "+cus;wm("sl"); // Display date. } //----------------------------------- Variable Updates ---------------------------------- if(cs.Equals("bt1")) { // If button clicked wm("l"); // Add "leave as is" tag < pre> to cis cis+="c_a=";ks="c_a";wm("vg");om("ti"); // Get application var, convert to int o++;om("fi");cis+=os;ks="c_a";wm("vs"); // increment it,display it,save it. cis+=" c_s=";ks="c_s";wm("vg");om("ti"); // Do same to session var. o++;om("fi");cis+=os;ks="c_s";wm("vs"); cis+=" c_p=";ks="c_p";wm("vg");om("ti"); // Do same to page var. o++;om("fi");cis+=os;ks="c_p";wm("vs"); wm("c"); // Close all HTML tags cs="lb01";ds="c";wm("sl"); // Display text in (cis) } } } ========================================================================================= TUTORIAL: CALENDAR CONTROL: There are 3 settings which you need to know about when you install a calendar control: (1) Availability of grid seperation lines: If you want them to appear, supply (ib=true;) (2) Cell Spacing: You may specify the seperation line width in pixels assigned to (kd) (3) Border: If you want a border around the calendar assign its width in pixels to (jd) VARIABLES: Practice with clicking the button to see how each of the 3 variables react when you do it. Then do the following: (1) Close the browser window then start a new one. You'll find that all 3 counters have been reset. This is because your session has been the only one requesting the page. When it was terminated the page was closed. So all var's lost their values. (2) Start a second browser window, load the same page and cilck the button 3 times. Return back to first window and click the button once. You'll notice that all counters have advanced by 1 except c_a which has advanced by 4. This is because application variables are common for the two sessions while both page and session variables are not. (3) Leave the first window untouched until the session times out (normally in 20 minutes), then click the button once. You'll notice that the session variable c_s is the only one which has been reset. The page and application var's have stayed the same. =========================================================================================


WORKING WITH MORE COMPLICATED FORMS ===================================== FORM CONTROLS: Here is a list of the most commonly used controls in forms: TEXT FIELD: This is the most common control in forms. Here are some of its setup features: (1) To make it a "Password field", add (ib=true) to its setup parameters. (2) To make it "Read Only" text field, add (ob=true). (3) To make it large enough for (n) chars, all visible, add (jf=n) (4) To make it large enough for a maximum of (m) chars (visible and invisible), add (od=m) (5) To make it contain a default text, add (cus="the text") TEXT AREA: This is a multi-line text field. Here are some of its setup features: (1) To make it "Read Only" text field, add (ob=true). (2) To make it large enough for (x) chars and (y) lines, all visible, add (jf=x;kf=y;) (3) To make it large enough for a maximum of (m) total chars (visible and invisible), add (od=m) (4) To make it contain a default text, add (cus="the text") CHECK BOX: We use it when we expect the user to select more than one item. To make it "selected" by default, add (cus="1") to its setup parameters. RADIO BUTTON: We use it when we expect the user to select only one item. To make it "selected" by default, add (cus="1") to its setup parameters. Naming Check Boxes and Radio Buttons: ------------------------------------- These two control types are used as groups. You may include more than one group of Check boxes or Radio Buttons in your form. This requires a special naming convention. The keyname for any control of these two types must be made of 4 chars like "rb25". In this name "2" is the group number which this Radio Button belongs to. You can create upto 9 Check Box groups and 9 Radio Button groups. Their numbers should be between 0 to 8. Group number "9" is reserved for internal use. Each group may contain upto 10 individual buttons identified by the digits (0:9). So "rb25" is Radio button number 5 (which is the sixth button) of group 2. DROP DOWN LIST: --------------- This control allows the user to select an item from a list of items. To supply the item list assign it to CIS[]. You may make the first item (which is CIS[0]) the title of the Drop Down List or make a seperate label for the "Drop Down List" assigned to (cis) as you do with other controls. To set a default selection, assign the index of the item to be selected to (cui). CONTROL LABELS: --------------- We always assign the label to (cis). The label of a Button and the label of a "Label control" are printed on them. The size of the label actually sets the size of those two controls. You can always resize those controls by changing the font size or text of their labels. For a "Check Box" and "Radio Button", the label always sets to the right of the control. For most other controls we can do a lot more with labels. We can set them above, below, to the left or to the right of their controls. We can also load them with the html necessary to set their color, fonts, locations and much more. We have already done some of that in previous examples. To set the label location relative to its control assign the label direction code to (os) the label direction code can be ("n","s","e" or "w") meaning that the label should be set (above, under, right of or left of) its control (respectively) The default is "n". For a Drop Down List control, We may use the top item of its item list as the label. If we decide to do so, we make no assignment to (cis) and assign the label to CIS[0] instead. OTHER COMMON SETUPS: -------------------- (1) cs: Keyname of the control. It identifies the control. It is made of the two characters which identify the control object followed with any number in the range "0:99". (2) cns: Keyname of the control's container. The container can be either a table or a panel with scroll bars. (3) (j,k): Order of the first cell in the table container which the control occupies horizontally and vertically. (4) (i,o): Number of cells which the control occupies horizontally and vertically. (5) (lf,of): Width and Height in Pixels. (6) jd: Border width (7) cls: Combined Foreground-Background color code. (8) fns: Font code. (9) cts: Tooltip's text which appears when mouse pointer is placed over the control. (10) id: Tab index. Sets the order at which you move through controls by using the Tab key. SUBMITTING THE FORM: -------------------- We expect you to include a button which the user clicks after completing a form. ASP.NET allows most controls to generate their own events when the user changes their content. This means that if the user types something wrong into a text field or checks a check box by mistake, the data may immediately be sent to the server. We don't receive such events since the user must be allowed to inspect what he/she has done and make all the corrections necessary before submitting the form. However, if you like to handle the events of any control by yourself, you can always get the control's object by assigning its keyname to (cs) and calling wm("O") [This is the upper case letter 'O']. We handle only 3 events, "Page_Load", "Button_Click" and "ImageButton_Click" GETTING CONTROL's UPDATE: ------------------------- After the user hits the "Submit" button, PC# receives the event, obtains the keyname of the button and assigns it to (cs), then calls method update(). In method update(), the first thing to do is to use method wm("gu") to get the latest update for all the controls which you expect the user to have changed. Here is how it works for each control: TEXT FIELDS AND TEXT AREAS: Calling the method returns the text which the user has entered assigned to (cus) DROP DOWN LISTS: Calling the method returns the selected item's index assigned to (cui) CHECK BOXES AND RADIO BUTTONS: These controls can either be checked individually or as groups. To check them individually, assign the control's keyname to (cs) and call wm("gu"). If the control was selected, you will receive (cus="1"). If it was not, you will receive (cus="") or (cus="0"). To check them as groups, let us have some application examples: Check box groups: Assume that your form contains a check box group which is made of "cb10","cb11","cb12". As you must know, the group number of the three button group is "1". To check the update of this group call the method as follows: cs="cb1*";wm("gu"); The method will return the control update array CUS[] containing "1" into each row which represents a checked button and "0" into each row which represents a button which has not been checked. Each button is represented by the row whose index number is the same as the button's index number within its group (which is the last digit in its keyname). So, if the user has checked "cb10" and "cb12" and left "cb11" unchecked, you'll get: CUS[0]="1", CUS[1]="0" and CUS[2]="1". Radio Button groups: For a Radio button group made of the four buttons "rb30","rb31", "rb32" and "rb33" you check the group's update by: cs="rb3*";wm("gu"); The method will return the control update integer (cui) assigned the order of the selected button. So, if the user has selected "rb32", you'll get (cui=2). Example 4: We'll demonstrate the installation and event handling of a form which contains Text fields, Text area, Drop Down List, Check box group and Radio Button group in addition to Labels and Buttons. IMPOTANT: We have replaced the html linefeed code with "[br]" in order to make your browser display it properly. You need to replace the square brackets with angled brackets in your code file. ========================================================================================= public partial class pg4:master1 { public override void init() { base.init(); } public override void setup() { base.setup(); // Run setup() of master page first //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 made of 3 col's, 5 rows cs="lb0";cis="Personal Information";j=0;k=0;i=3;ds="c";cls="s9G1";fns="trb14";wm("i"); cs="tf0";cis="First Name";j=0;k=1;jf=17;ds="w";cls="b0o5";fns="trb12"; cts="Your First Name";wm("i"); // Tool tip added to this control cs="tf1";cis="Last Name";j=1;k=1;i=2;jf=15;ds="e";cls="b0o5";fns="trb12";wm("i"); cs="tf2";cis="Street Address";j=0;k=2;i=3;jf=44;ds="w";cls="b0o5";fns="trb12";wm("i"); cs="tf3";cis="City";j=0;k=3;jf=15;ds="w";cls="b0o5";fns="trb12";wm("i"); cs="tf4";cis="State";j=1;k=3;jf=5;ds="w";cls="b0o5";fns="trb12";wm("i"); cs="tf5";cis="Zip";j=2;k=3;jf=5;ds="w";cls="b0o5";fns="trb12";wm("i"); cs="ch0";cui=0;j=0;k=4;i=2;ds="w"; // 1st item is the title CIS=new string[]{"Years at this residency","Less than Two years","Two Years or more"}; cls="b0o7";fns="trb12";wm("i"); cs="bt0";cis="Submit";j=1;k=4;ds="e";cls="r0";fns="trb12";wm("i"); //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 contains following items cs="lb1";cis="Additional Information";j=k=0;i=3;ds="c";cls="s9G1";fns="trb14";wm("i"); cs="lb2";cis="Optional Information:";j=0;k=1;ds="w";cls="b0p7";fns="trb12";wm("i"); cs="cb00";cis="Over 65";j=1;k=1;ds="w";cls="b0p7";fns="trb12";wm("i"); cs="cb01";cis="Retired";j=2;k=1;ds="e";cls="b0p7";fns="trb12";wm("i"); cs="lb3";cis="Method of payment:";j=0;k=2;ds="w";cls="r0p7";fns="trb12";wm("i"); cs="rb00";cis="MasterCard";cus="0"; // First button selected as default j=1;k=2;ds="w";cls="r0p7";fns="trb12";wm("i"); cs="rb01";cis="Visa";cus="1";j=2;k=2;ds="e";cls="r0p7";fns="trb12";wm("i"); cs="tf6";cis="Credit Card number";j=0;k=3;jf=19;ds="w";cls="S9s9";fns="trb12";wm("i"); cs="tf7";cis="Exp Date";j=1;k=3;jf=5;ds="c";cls="S9s9";fns="trb12";wm("i"); cs="tf8";cis="V Code";j=2;k=3;jf=3;ds="e";cls="S9y7";fns="trb12";wm("i"); cs="ta0";cis="Special Instructions";j=0;k=4;i=3;o=2;jf=34;kf=2;ds="w"; cls="S9g8";fns="crb12";wm("i"); cs="bt1";cis="Submit";j=2;k=6;i=3;ds="c";cls="r0";fns="trb12";wm("i"); } //----------------------------------------------------------------------------------- public override void update() { //------------------------------------ Page Load ------------------------------------ if(cs.Equals("pl")) { // If event is "Page_Load" setup(); // Execute setup() MakePage(table); // Make the page PageNumber(4); // Call master1 class's method } // to display this page's number //------------------------------------ bt0 Click ------------------------------------- if(cs.Equals("bt0")) { // If "bt0" clicked // Var's used: ns=Name, rs=Years of residency // Will check tf0, tf1 & ch0 // only as samples. cs="tf0";wm("gu");ns=cus+" "; // assign First name to (ns) cs="tf1";wm("gu");ns+=cus; // add last name to (ns) cs="ch0";wm("gu"); // Get ch0's update (cui=sel indx) if (cui==1) rs="Less than 2";else if (cui==2) rs="Two or more"; cis+="Name: "+ns+"[br]"+"Residency years: "+rs; // Make output string cs="lb00";wm("sl"); // Display it into "lb00" } //------------------------------------ bt1 Click ------------------------------------- if(cs.Equals("bt1")) { // If "bt1" clicked // Var's used: ps=Optional Information, ds=Credit Card Name cs="cb0*";wm("gu"); // Get update for checkbox group if (CUS[0].Equals("1")) ps+="Over 65,"; // Assign selected item(s) to (ps) if (CUS[1].Equals("1")) ps+="Retired,"; cs="rb0*";wm("gu"); // Get update for Radio Button grp if (cui==0) ds="MasterCard";else ds="Visa"; // Assign selected item to (ds) cis+="Op. Information: "+ps+"[br]"+"Credit Card: "+ds; cs="lb01";wm("sl"); // Display results } } } =========================================================================================


DATA VALIDATION =============== The asp.net allows validating data entered by users into a form at their browser before sending the data to the server. This saves time especially at high traffic time when it takes too long to make a trip to the server and back. PC# has simplified the validation process significantly. All you do is add between 1-3 parameters to your control's setup data to do the validation. There are 4 types of client side validations: (1) REQUIRED FIELD VALIDATION: This is to insure that the user has entered data into the field before clicking the submit button. If the user has not, he gets a message to remind him to do so and the data is not sent to the server. (2) RANGE VALIDATION: If the data entered into the field was outside expected range, a warning message is given to the user and the data is not sent to the server. (3) COMPARE VALIDATION: If the data entered into the field was higher, lower, equal or not equal to a specific value or to the data entered into another field, the user gets a warning message and the data is not sent to the server. (4) REGULAR EXPRESSION: If the data entered into the field does not conform to a specified Regular Expression formula, the user gets a warning message and the data is not sent to the server. HOW TO DO IT: There are three variables which control the validation process. These variables are (vlb, vlc and vls) As you must know their types are (bool, char and string) respectively. You may add one or more of these variables to the setup data of one control in order to validata its data. Here are all the options: (1) If you don't want to validate a field, add none of them to its setup data. (2) If you like to make sure that the field is not blank, add (vlb=true;) (3) If you like to make sure that the data entered is within a particular range, assign the two limits to (vls) and the type code to (vlc) as will be explained next. (4) If you like the data entered into a field to be compared against a value or against data entered into another field, assign an expression indicating the comparison wanted to (vls) and the data type which the comparison will be based on to (vlc) (5) If you like the data entered into a field to be compared against a regular expression string, assign the RegularExpression string to (vls) and assign 'r' to (vlc) HOW TO PREPARE (vls): --------------------- To do range validation: vls=min:max where min and max are the minimum and maximum allowed limits respectively. Example:vls="0:5" means that data in the field must not be outside the range 0:5. To do compare validation: Assign the operation followed with the value or control to compare with to vls. Operation can be one of (=, !=, <, <=, >, >=) Examples: vls="=5" means that data entered into the field must be equal to "5". vls="!=5" means that data entered into the field must not be equal to 5. vls="=tf0" means that data entered into the field must be equal to the data entered into the field (tf0) HOW TO PREPARE (vlc): --------------------- vlc is assigned the code for the type upon which the comparison is based. It can be: i=int d=double s=string D=date C=Currency. Example: vlc='i' means compare the two values as integers. vlc='s' means compare the two values as strings. REGULAR EXPRESSIONS: (For versions 1.70 or later) -------------------- The Regular expression for a phone number (at USA) is "^\(?\d{3}\)?(\s|-)?\d{3}-\d{4}$". If someone has told you that he's willing to write the code to validate your user's data for you but you have to figure out the regular expression formula for each field, I think you could have told him that you would rather write the validation code and let him figure out the formulae! With client-side validation, it could be worth it to do. This is because you can't do the validation at the client side by yourself but the ASP.NET can. This will actually be changed when you learn how to add JavaScript to your code in WPDIII and WPDIV. Here are the RegularExpression strings for some data types: Socia Security Numbers: vls=@"\d{3}-\d{2}-\d{4}"; Phone numbers (USA) : vls=@"^\(?\d{3}\)?(\s|-)?\d{3}-\d{4}$"; Password with 6 char's minimum length that contains a digit or '.': vls=@"(?x)^(?=.*( \d | \p{P} | \p{S} )).{6,}"; REMARK: ======= The '@' symbol at the start of each string is to instruct the compiler not to worry about escape sequence. This is because RegularExpression strings normally contain '\' char's which must be left unchanged. COMPARING CLIENT SIDE TO SERVER SIDE VALIDATION: ------------------------------------------------ Client side validation saves time, so it is good to use for most simple validations. However, you must know that this "mechanical" kind of validation is never a match to the server side validation in which you use your full programming ability and resources to insure that the data entered by the user is valid. EXAMPLE 5: This example shows how to do both client side and server side validation. IMPOTANT: We have replaced the html linefeed code with "[br]" in order to make your browser display it properly. You need to replace the square brackets with angled brackets. ========================================================================================= public partial class pg5:master1 { public override void init() { base.init(); } public override void setup() { base.setup(); // Run setup() of master page first //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 contains following items cs="lb0";cis="Personal Information";j=0;k=0;i=3; // Form title ds="n";cls="s9G1";fns="trb14";wm("i"); cs="tf0";cis="User ID";vlb=true;j=0;k=1;i=0;jf=18; // User ID, RequiredField ds="w";cls="b0o5";fns="trb12";wm("i"); // validation (RFV) only cs="tf3";cis="Phone number";j=1;k=1;i=2;jf=18; // Phone number: RequiredField also vlb=true;vls=@"^\(?\d{3}\)?(\s|-)?\d{3}-\d{4}$";vlc='r'; ds="e";cls="b0o5";fns="trb12";wm("i"); // reg expression validation required cs="tf1";cis="Password";vlb=true;j=0;k=2;ib=true; // Password, RFV only. (ib=true) jf=18;ds="w";cls="b0o5";fns="trb12";wm("i");// makes it a password field. cs="tf2";cis="Password Again";j=1;k=2;i=2;ib=true; // "Pass Again" field. RFV+Compare vlb=true;vls="=tf1";vlc='s';jf=18; // validation based on "String" ds="e";cls="b0o5";fns="trb12";wm("i"); // data type. cs="lb1";cis="Method of payment:";j=0;k=3;ds="w";cls="b0p7";fns="trb12";wm("i"); cs="rb00";cis="MasterCard";cus="0";j=1;k=3;ds="w";cls="b0p7";fns="trb12";wm("i"); cs="rb01";cis="Visa";cus="1";j=2;k=3;ds="e";cls="b0p7";fns="trb12";wm("i"); cs="tf6";cis="Credit Card number";vlb=true;j=0;k=4; // Card number, RFV only. This jf=19;ds="w";cls="S9s9";fns="trb12";wm("i");// field also validated at server cs="tf7";cis="Exp Date";vlb=true;j=1;k=4;jf=5; // Exp Date, RFV only. This field ds="c";cls="S9s9";fns="trb12";wm("i"); // is also validated at server. cs="tf8";cis="V Code";vlb=true;vls="0:999";vlc='i'; // RFV + Range validation as (int) j=2;k=4;jf=3;ds="e";cls="S9y7";fns="trb12";wm("i"); cs="bt0";cis="Submit";j=2;k=6;i=3;ds="c";cls="r0";fns="trb12";wm("i"); //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 contains following items cs="lb3";cis="Validation";j=0;k=0;i=3;ds="n"; // Title cls="s9G1";fns="trb14";wm("i"); cs="vs0";j=0;k=1;i=3;cls="r0p7";fns="trb12";wm("i");// Validation Summary Control cs="lb4";j=0;k=2;i=3;cls="r0p7";fns="trb12";wm("i");// Label to display server valid. } //----------------------------------------------------------------------------------- public override void update() { //------------------------------------ Page Load ------------------------------------ if(cs.Equals("pl")) { // If event is "Page_Load" setup(); // Execute setup() MakePage(table); // Make the page PageNumber(5); // Call master1 class's method to } // to display this page's number //------------------------------------ bt0 Click ------------------------------------- if(cs.Equals("bt0")) { // Var's used: ns=C Card Number after non-digit char's removed, a=asc code // m,y=Month, Year entered by user. a,b=This Month, This Year // es=Error Message string // ------------------------ Validating Credit Card Number ------------------------ cs="tf6";wm("gu"); // Get Card Number text into (cus) ns="";es=""; // Initialize both strings char[] CC=cus.ToCharArray(); // Convert cus to Char Array for(int i=0;i< cus.Length;i++) { // Scan (cus) characters a=(int)CC[i]; // Get asc value of each char if(a>47 && a< 58) ns+=CC[i]; // If a digit, add char to (ns) } if (ns.Length!=16) es+="* Please re-enter your Credit Card Number.[br]"; // If resulting (ns) was not 16 // digits long, add error message // -------------------- Validating Credit Card Expiration Date -------------------- cs="tf7";wm("gu"); // Get Expiration Date into (cus) if (cus.Length<5 || cus.IndexOf("/")<2) { // If not 5 chars long and contains es+="Please re-enter your Credit Card Expiration Date."; } // (/) at the middle, add error msg else { // Else: os=cus;oc='/';om("s"); // Seperate month, year os=OS[0];om("ti");m=o; // Convert each to type (int) and os=OS[1];om("ti");y=o; // assign to m,y respectively. os="";sm("dd"); // Get today's date in short format os=os.Substring(0,3)+os.Substring(8,2); // Pick (mm/yy) section oc='/';om("s"); // Seperate month, year os=OS[0];om("ti");a=o; // Convert each to type (int) and os=OS[1];om("ti");b=o; // assign to a,b respectively if (y< b || (y==b && m< a)) es+="* Your Credit Card has expired."; } // Compare enterd (m,y) with (a,b) // Add error msg if card expired. if (es.Length==0) es="* Thank you. You have completed the form successfully."; // If no error added so far, add // "Successful data entry" message cs="lb4";cis=es;wm("sl"); // Display error msg string at lb4 } } } =========================================================================================


GRAPHICS ========== Including dynamically generated Graphics into your web pages has become a very simple task, thanks to the techniques PC# uses for drawings. If you remember, when you draw on a window form, you don't draw on the form directly. Instead, you draw on the Default Graphical Device (bio) which is a bitmap object large enough to take all your drawings and is created automatically for you during initialization. This is exactly what you need when you draw on a web page. When you write a web page class which extends class (pasp), you have no window form to draw on, but the Graphical Output Device (bio) is still available. So, you use the same code which you could have used if you have been drawing on a window form with absolutely no change. PC# will then send (bio) with all your drawings dynamically to your page. Now, you may like to ask "Can the drawings be included into the same class with all other controls?". Not easily, we'll see how to get it all done in one file later, but by now we need to prepare at least two classes, the main class which includes the setup data for all controls and one class for each drawing. The main class should include an Image control for each drawing it needs to generate. The file name specified for each image control must match the name of the ".aspx" file of the drawing class. The reason for not mixing the main class with the drawing classes is that each page must have its "Content Type" specified. The content type of the main page is "text/html" while the content type of the drawing page is "image/jpeg". Your drawing class is exactly the same as any page class. It extends (pasp) class and should be saved into a ".cs" file then tool "pcw" should be used to create its ".aspx" file. The drawing class should include no setup() method. All drawing code should be in method update(). Here is how to make your drawing code: (1) Open a new dynamic bitmap drawing operation. This is done by calling method wm("bo") after assigning the wanted width and height of (bio) to (lf,of) respectively. (2) Write your drawing code exactly as you do when you draw on a window form. (3) Close the bitmap drawing operation. This is done by calling wm("bc"). This will save your bitmap (bio) to the page's output stream then dispose all graphical objects. EXAMPLE 6: We are going to see how to modify the code used in window form's drawing examples which we have seen before so that they draw dynamically into a web page. Desktop Graphics example 8 was to draw a piece of jewelry. Since the only advantage in dynamic web drawing is in allowing user interaction, we'll modify that example so it allows the user to select the pearl colors. Also, Desktop Graphics example 13 has demonstrated how window form controls and drawings can interact together. It showed how to draw a triangle, square, circle and a pentagon using colors which are selectable by the user. We'll see how to modify it so it does the same accross the web. ========================================================================================= THE MAIN CLASS (class pg6) -------------------------- public partial class pg6:master1 { // Class extends master1 as usual public override void init() { base.init(); // Initialize pasp } public override void setup() { base.setup(); // Execute setup() of master1 class //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 2 cols, 2 rows cs="ch0";j=0;k=0;ds="c";cls="S9g7";fns="trb12"; // Pearl color drop list CIS=new string[]{"Pearl Color","Red","Green", // First item is the title "Blue","Magenta","Cyan","Orange","Pink","Yellow"};wm("i"); cs="bt0";j=0;k=1;cis="Redraw";cls="r0g7";fns="trb12";ds="c";wm("i"); // Redraw button cs="im1";cis="";j=1;k=0;o=2;ds="c";lf=of=200; // Image control where the drawing ims="jewel.aspx";wm("i"); // will be, ims=the ".aspx file" //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 3 cols, 2 rows cs="ch1";j=0;k=0;ds="c";cls="S9g7";fns="trb12"; // Shape selection drop list CIS=new string[] {"Select a Shape", // First item is the title "Triangle","Square","Circle","Pentagon"};wm("i"); cs="bt1";j=1;k=0;cis="Redraw";cls="r0g7";fns="trb12";ds="c";wm("i"); // Redraw button cs="ch2";j=2;k=0;ds="c";cls="S9g7";fns="trb12"; // Shape color drop list CIS=new string[] {"Select a Color","Red","Green","Blue","Black"};wm("i"); cs="im2";j=0;k=1;i=3;ds="c";lf=370;of=200; // Image control sets drawing ims="shapes.aspx";wm("i"); // location and file name } //----------------------------------------------------------------------------------- public override void update() { //------------------------------------ Page Load ------------------------------------ if(cs.Equals("pl")) { // If event is "Page_Load" setup(); // Execute setup() if(!IsPostBack) { // If first trip to retrieve page ks="PearlColor_s";os="p0";wm("vs"); // Save initial color code ("p0") // as a session variable ks="shapes_s";os=" ";wm("vs"); // Save initial "shape colors" } // string also as a session variable MakePage(table); // Make the page to be sent PageNumber(6); // Call master1 class's method to } // set page number. //------------------------------------ bt0 Click ------------------------------------- if(cs.Equals("bt0")) { // If button (bt0) clicked: cs="ch0";wm("gu"); // Get ch0's update (cui=index) os=" rgbmcopy".Substring(cui,1)+"0"; // Form color code if (cui==0) os="p0"; // if (cui=0) use default color. ks="PearlColor_s";wm("vs"); // Save selected color as a session } // variable. //------------------------------------ bt1 Click ------------------------------------- if(cs.Equals("bt1")) { // If button (bt1) clicked: // var's used: x=Order number of selected shape in (ch0) // ys=Order number of selected color in (ch1) converted to string cs="ch1";wm("gu"); // Get ch1's update, assign selected x=cui-1; // index to (x) after being adjusted // (since 1st item is title) cs="ch2";wm("gu"); // Get ch2's update. If was item 0, ys=" "; // assign space to (ys) if (cui>0) ys=""+(cui-1); // else ys=adjusted (cui) as string ks="shapes_s";wm("vg"); // Get stored shape colors string. if(os.Length<4 || x==-1) {os=" ";x=0;} // If not valid or if user selected // item 0 (which means no selection) // fill all 4 positions with spaces os=os.Substring(0,x)+ys+os.Substring(x+1); // Else put user selected index at // correct position of the string ks="shapes_s";wm("vs"); // Save string as a session variable } } } CLASS jewel ----------- public partial class jewel:pasp { // Class extends (pasp) which // contains all PC# methods public override void init() { base.init(); // Initialize pasp } public override void update() { if(cs.Equals("pl")) { // If event is "Page_Load" lf=of=200;wm("bo"); // Open new bitmap operation using bitmap of // size 200 X 200 pixels. cls="p7";gm("ec"); // Paint background with same color as page // ----------- This section is copied from the Window forms drawing example ----------- // ----------------------- Except for the lines marked with '**' ---------------------- lf=of=170;gm("ce"); // Create the circular gold plate cls="o5y5";gm("spl"); // Prepare linear gradient brush for it gm("grf"); // then render-fill the gold plate. lf=6;of=50;gm("c="); // Create hexagon shape object at center. cls="r0";ks="r";gm("grs"); // Draw the object using sp effects-refl at jf=45;cls="b0";ks="r";gm("grs"); // center in red, then repeat 6 times using jf=-45;cls="b0";ks="r";gm("grs"); // different colors and different locations jf=22;kf=40;cls="g0";ks="r";gm("grs"); jf=-22;kf=40;cls="m0";ks="r";gm("grs"); jf=22;kf=-40;cls="m0";ks="r";gm("grs"); jf=-22;kf=-40;cls="g0";ks="r";gm("grs"); lf=of=25;gm("ce"); // Create a circle at center (pearl) ks="PearlColor_s";wm("vg"); // ** get color code stored as session var if(os.Length<2) os="p0"; // ** If not valid use pink color as default cls=os; // ** Assign code to (cls) for (int x=0;x<20;x++) { // Draw it 20 times using sp effects-refl. jf=80;kf=18*x;kb=true; // at locations around the plate. Polar ks="r";gm("grs"); // coord's are used for specifying locations } // ------------------------------------------------------------------------------------- wm("bc"); // Close bitmap operation } } } CLASS shapes: ------------- public partial class shapes:pasp { public override void init() { base.init(); } public override void update() { // var's ss=Shape colors // ss is a 4 char string representing the 4 // s=Shape's order number // shapes in order. Each char contains the // c=Color order number // order of the color code to draw the shape // it represents with. if(!cs.Equals("pl")) return; // If not Page_load event, return ks="shapes_s";wm("vg");ss=os; // Get ss string stored as session variable if(ss.Length<4) ss=" "; // If var lost or corrupted use default lf=370;of=200;wm("bo"); // Open new bitmap operation using bitmap of // size 370 X 200 pixels cls="p7";gm("ec"); // Match image background color with page's string mode; // Mode can be "f" / "d" meaning fill or draw for (s=0;s < ss.Length;s++) { // Scan (ss) characters os = ss.Substring(s,1); // Assign each char to (os) if (os.Equals(" ")) c=-1; // If os=space, Color is indeterminable, make else { // (c=-1) else: om("ti");c=o; // convert (os) to int and assign to c cls="r0 g0 b0 S9 ".Substring(3*c,2); // Get (cls) for selected color } mode="f";if(c==-1) {cls="S9";mode="d";}// If (c=-1),object will be drawn in black gm("sps"); // Create solid pen/brush for the color if (s==0) { // For item 0, draw-fill triangle jf=-125;kf=45;lf=3;of=95;ls="c="+mode;gm(); } else if (s==1) { // For item 1, draw-fill square jf=125;kf=50;lf=of=70;ls="cr"+mode;gm(); } else if (s==2) { // For item 2, draw-fill circle jf=-125;kf=-50;lf=of=85;ls="ce"+mode;gm(); } else if (s==3) { // For item 3, draw-fill pentagon jf=125;kf=-50;lf=5;of=95;ls="c="+mode;gm(); } } wm("bc"); // Close bitmap operation. } } ========================================================================================= HOW TO GENERATE NECESSARY FILES: (1) Save all three classes into code files, named "pg6.cs", "jewel.cs" and "shapes.cs". (2) Use the tool (pcw) to generate necessary (.aspx) files as follows (from command mode): pcw pg6 [ENTER] pcw jewel [ENTER] pcw shapes [ENTER] This should generate the files "pg6.aspx", "jewel.aspx" and "shapes.aspx". The only file the user needs to know about is "pg6.aspx". When this file is requested by the browser all files will be used together to generate the page. ========================================================================================= TUTORIAL: Here are some comments: (1) The main page and the graphics pages are seperate pages, so in order to make them communicate we cannot use page variables, we must use at least session variables. (2) In the update() method of the main class, user selection is received and stored as session variables, which are read by the graphics classes and their drawings are set accordingly. (3) The "Drop Down List" (Sorry its symbol is 'ch' because we used to call it "choice") when its update is requested using wm("gu"), returns to us the user selection in the form of an integer assigned to its control update variable (cui). The value in (cui) is the order number of the selected item within all items of the list. The first item (cui=0) is the list's title. If the user has selectsd this item, it means that he has made no choice. In case of the Jewelry drawing, we have considered this to be an indication that the user wants to select the default color. In case of the Shapes drawing, we have cosidered selecting no color for a shape to mean that the user wants to draw the shape without filling. (4) In case of the Jewelry drawing, the item to pass from the main class to the drawing class is the pearl's color code. In case of the Shapes drawings, we have 4 shapes each of them may be drawn in one of 4 colors. So, we have used a 4 char long string, each of its char's represents one shape at the same order as their orders in the list which is (Triangle-Square-Circle-Pentagon). We insert at each character the order number of the color the user wants to draw the shape in. A space at the location of one shape means that the user wants to draw that shape without filling. At the start the string contains 4 spaces, so all shapes are drawn without filling. (5) A Graphics class is the same as any page class except that it contains no setup() method and it receives only one event which is the "Page_Load". When this event is received, it generates its drawings. We make (.aspx) files for them as we do with all other page classes. (6) Notice that none of the code files are compiled. The ASP.NET receives them as is and compiles them internally. The only file which has been compiled is the master class. it is compiled into the library file (master1.dll) which must reside into the "Bin" sub directory of the application directory. CAN WE COMBINE THE 3 FILES INTO ONE? ==================================== You maybe wondering if we can eliminate the two graphic generating files "jewel" and "shapes" and combine them with "pg6" file. Yes we can if we use "Query Strings". You know that you can combine several applications into one desktop program by writing the code of each application into a seperate block or group of blocks. Then, using command line arguments to execute each application individually. If you don't remember how it is done, see the section of the Reference manual for desktop applications under the title "Command Line Arguments". In Web applications, we can do the exact same thing using "Query string". Query String: Query string does the same as command line arguments for web pages. To add arguments to a web page add the question mark symbol '?' at the end of the page's URL followed with a combination of "Key=Value" elements. For example: http://www.xxx.com?x=50 will take you to the page at "http://www.xxx.com" and lets the page know that the value of key (x) is "50". One important thing to know is that all keys are considered to be of type string, so the query string (x=50), actually mean that the string (x) is equal to "50". Method wm() at mode "rq" reads the query string for you and extracts the values which corresponds to any key which you supply it with. Notice that in general, each key may have more than one value. Here is how to do it, if you like to get the value of key (x) in the example above you would supply the name of the key to (ks) and call the method as follows: ks="x";wm("rq"); The value returned is the array OS[] containing all the values which correspond to key (x). Since you are expecting only one value, your value will be stored into the first element, so you should get OS[0]="50" and all other array elements should be empty. If the URL used to retrieve the page contained no query string you should get OS[0]="" and all other elements of the array should return the same value. Now let us see how to modify the file "pg6.cs" so files "jewel.cs","jewel.aspx", "shapes.cs" and "shapes.aspx" can be all eliminated. (1) In method setup(), the two image files "jewel.aspx" and "shapes.aspx" which are used for the setup of controls "im1" and "im2" will be renamed to "pg6?block=1" and "pg6?block=2" respectively. This means that they will be in the same page at different blocks. (2) The code used to generate the drawings will be moved to methods jewel() and shapes() located into "pg6.cs". (3) At the start of method's update, the value of the query string "block" will be obtained and if found to be equal to "1" or "2", the corresponding drawing method will be executed. Notice that class "pasp" which we are extending, does not have a definition for the old block number variables (bli) and (blp). The block which we are now using is of a string type and you must define it at the top of the page class. This means that you can rename it as you like too. Here is the new modified listing of "pg6.cs": ========================================================================================= public partial class pg6:master1 { // Class extends master1 as uasual string block=""; // Declare the string var (block) public override void init() { base.init(); // Initialize pasp } public override void setup() { wm("ir"); // Reset installation par's since // wm("rq") could have altered some base.setup(); // Execute setup() of master1 class //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 2 cols, 2 rows cs="ch0";j=0;k=0;ds="c";cls="S9g7";fns="trb12"; // Pearl color drop list CIS=new string[]{"Pearl Color","Red","Green", // First item is the title "Blue","Magenta","Cyan","Orange","Pink","Yellow"};wm("i"); cs="bt0";j=0;k=1;cis="Redraw";cls="r0g7";fns="trb12";ds="c";wm("i"); // Redraw button cs="im1";cis="";j=1;k=0;o=2;ds="c";lf=of=200; // Image control where the drawing ims="pg6.aspx?block=1";wm("i"); // will be, same page. //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 3 cols, 2 rows cs="ch1";j=0;k=0;ds="c";cls="S9g7";fns="trb12"; // Shape selection drop list CIS=new string[] {"Select a Shape", // First item is the title "Triangle","Square","Circle","Pentagon"};wm("i"); cs="bt1";j=1;k=0;cis="Redraw";cls="r0g7";fns="trb12";ds="c";wm("i"); // Redraw button cs="ch2";j=2;k=0;ds="c";cls="S9g7";fns="trb12"; // Shape color drop list CIS=new string[] {"Select a Color","Red","Green","Blue","Black"};wm("i"); cs="im2";j=0;k=1;i=3;ds="c";lf=370;of=200; // Image control sets drawing ims="pg6.aspx?block=2";wm("i"); // location. } //----------------------------------------------------------------------------------- public override void update() { //------------------------------------ Page Load ------------------------------------ if(cs.Equals("pl")) { // If event is "Page_Load" ks="block";wm("rq");block=OS[0]; // Get the block number (string) if (block.Equals("1")) {jewel();return;} // Call jewel() if block="1" if (block.Equals("2")) {shapes();return;} // Call shapes() if block="2" // If neither one, do: setup(); // Execute setup() if(!IsPostBack) { // If first trip to retrieve page ks="PearlColor_s";os="p0";wm("vs"); // Save initial color code ("p0") // as a session variable ks="shapes_s";os=" ";wm("vs"); // Save initial "shape colors" } // string also as a session variable MakePage(table); // Make the page to be sent PageNumber(6); // Call master1 class's method to } // set page number. //------------------------------------ bt0 Click ------------------------------------- if(cs.Equals("bt0")) { // If button (bt0) clicked: cs="ch0";wm("gu"); // Get ch0's update (cui=index) os=" rgbmcopy".Substring(cui,1)+"0"; // Form color code if (cui==0) os="p0"; // if (cui=0) use default color. ks="PearlColor_s";wm("vs"); // Save selected color as a session } // variable. //------------------------------------ bt1 Click ------------------------------------- if(cs.Equals("bt1")) { // If button (bt1) clicked: // var's used: x=Order number of selected shape in (ch0) // ys=Order number of selected color in (ch1) converted to string cs="ch1";wm("gu"); // Get ch1's update, assign selected x=cui-1; // index to (x) after being adjusted cs="ch2";wm("gu"); // Get ch2's update. If was item 0, ys=" "; // assign space to (ys) if (cui>0) ys=""+(cui-1); // else ys=adjusted (cui) as string ks="shapes_s";wm("vg"); // Get stored shape colors string. if(os.Length<4 || x==-1) {os=" ";x=0;} // If not valid or if user selected // item 0 (which means no selection) // fill all 4 positions with spaces os=os.Substring(0,x)+ys+os.Substring(x+1); // Else put user selected index at // correct position of the string ks="shapes_s";wm("vs"); // Save string as a session variable } } // ================================== jewel method ==================================== void jewel() { lf=of=200;wm("bo"); // Open new bitmap operation using bitmap of // size 200 X 200 pixels. cls="p7";gm("ec"); // Paint background with same color as page // ----------- This section is copied from the Window forms drawing example ----------- // ----------------------- Except for the lines marked with '**' ---------------------- lf=of=170;gm("ce"); // Create the circular gold plate cls="o5y5";gm("spl"); // Prepare linear gradient brush for it gm("grf"); // then render-fill the gold plate. lf=6;of=50;gm("c="); // Create hexagon shape object at center. cls="r0";ks="r";gm("grs"); // Draw the object using sp effects-refl at jf=45;cls="b0";ks="r";gm("grs"); // center in red, then repeat 6 times using jf=-45;cls="b0";ks="r";gm("grs"); // different colors and different locations jf=22;kf=40;cls="g0";ks="r";gm("grs"); jf=-22;kf=40;cls="m0";ks="r";gm("grs"); jf=22;kf=-40;cls="m0";ks="r";gm("grs"); jf=-22;kf=-40;cls="g0";ks="r";gm("grs"); lf=of=25;gm("ce"); // Create a circle at center (pearl) ks="PearlColor_s";wm("vg"); // ** get color code stored as session var if(os.Length<2) os="p0"; // ** If not valid use pink color as default cls=os; // ** Assign code to (cls) for (int x=0;x<20;x++) { // Draw it 20 times using sp effects-refl. jf=80;kf=18*x;kb=true; // at locations around the plate. Polar ks="r";gm("grs"); // coord's are used for specifying locations } wm("bc"); // Close bitmap operation } // ================================== shapes method ==================================== void shapes() { // var's ss=Shape colors // ss is a 4 char string representing the 4 // s=Shape's order number // shapes in order. Each char contains the // c=Color order number // order of the color code to draw the shape // it represents with. ks="shapes_s";wm("vg");ss=os; // Get ss string stored as session variable if(ss.Length<4) ss=" "; // If var lost or corrupted use default lf=370;of=200;wm("bo"); // Open new bitmap operation using bitmap of // size 370 X 200 pixels cls="p7";gm("ec"); // Match image background color with page's string mode; // Mode can be "f" / "d" meaning fill or draw for (s=0;s< ss.Length;s++) { // Scan (ss) characters os=ss.Substring(s,1); // Assign each char to (os) if (os.Equals(" ")) c=-1; // If os=space, Color is indeterminable, make else { // (c=-1) else: om("ti");c=o; // convert (os) to int and assign to c cls="r0 g0 b0 S9 ".Substring(3*c,2); // Get (cls) for selected color } mode="f";if(c==-1) {cls="S9";mode="d";}// If (c=-1),object will be drawn in black gm("sps"); // Create solid pen/brush for the color if (s==0) { // For item 0, draw-fill triangle jf=-125;kf=45;lf=3;of=95;ls="c="+mode;gm(); } else if (s==1) { // For item 1, draw-fill square jf=125;kf=50;lf=of=70;ls="cr"+mode;gm(); } else if (s==2) { // For item 2, draw-fill circle jf=-125;kf=-50;lf=of=85;ls="ce"+mode;gm(); } else if (s==3) { // For item 3, draw-fill pentagon jf=125;kf=-50;lf=5;of=95;ls="c="+mode;gm(); } } wm("bc"); // Close bitmap operation. } } ========================================================================================= TUTORIAL: The only item which requires a comment is calling wm("ir") at the top of method setup(). We know that the GUV's are guaranteed to be reset at the end of any method call no matter what the method or the mode is, but method wm() at mode "i" uses too many parameters, some of them are not reset by other methods or modes like (os) and (ob). Method wm() itself knows the parameters it uses at mode "i" and will reset them after each call. However, in this example, we called wm("rq") before calling wm("i") so we can't be 100% sure that all the parameters used by wm("i") have been reset before the call. Therefore calling wm("ir") at the beginning of setup() was good to do just to put us at the safe side.


EXAMPLE 7: Let us modify two more of the examples which we have studied in the "Drawing" section to make them web applications with user interaction. The two examples are: (1) Drawing example number 10 which shows how to draw text in a manner which makes you feel that it is elevated up or down. (2) Drawing example number 6 which compares four means which are used to give an object the 3D look. ========================================================================================= THE MAIN CLASS (class pg7) -------------------------- public partial class pg7:master1 { // Class extends master1 as uasual public override void init() { base.init(); // Initialize pasp } public override void setup() { base.setup(); // Execute setup() of master1 class //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 3 cols, 3 rows cs="lb1";cis="Select Text Elevation:";j=0;k=0;ds="w";cls="r0p7";fns="trb12";wm("i"); cs="rb00";cis="Up";j=1;k=0;ds="w";cls="r0p7";fns="trb12";wm("i"); cs="rb01";cis="Down";j=2;k=0;ds="e";cls="r0p7";fns="trb12";wm("i"); // 2 Radio Buttons and their label cs="tf0";j=0;k=1;i=2;ds="sw";cls="S9g7";fns="crb12";jf=20;od=20; cis="Enter upto 20 chars phrase";wm("i"); // Text field. Accepts upto 20 chars cs="bt0";j=2;k=1;cis="Start";cls="r0g7";fns="trb12";ds="se";wm("i"); // "Click to start drawing" button cs="im1";cis="";j=0;k=2;i=3;ds="c";lf=370;of=100; // Image control where the drawing ims="elevation.aspx";wm("i"); // will be, ims=the ".aspx file" //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 2 cols, 2 rows cs="ch1";j=0;k=0;ds="c";cls="S9g7";fns="trb8"; // 3D effects selection drop list CIS=new string[] {"Select 3D Effect", // First item is the title "Radial Gradient Paint","Linear Gradient Paint", "Sp Effects-Reflection","Sp Effects-Depth"};wm("i"); cs="bt1";j=0;k=1;cis="Start";cls="r0g7";fns="trb12";ds="c";wm("i"); // "Click to start drawing" button cs="im2";j=1;k=0;i=2;o=2;ds="c";lf=of=185; // Image control sets drawing ims="effects.aspx";wm("i"); // location and file name } //----------------------------------------------------------------------------------- public override void update() { //------------------------------------ Page Load ------------------------------------ if(cs.Equals("pl")) { // If event is "Page_Load" setup(); // Execute setup() if(!IsPostBack) { // If first trip to retrieve page ks="elevation_s";os="up";wm("vs"); // Save default values into session ks="phrase_s";os="Personal C Sharp";wm("vs"); // vars. Elevation="up", No special ks="effect_s";os=" ";wm("vs"); // effects are default values. } MakePage(table); // Make the page to be sent PageNumber(7); // Call master1 class's method to } // set page number. //------------------------------------ bt0 Click ------------------------------------- if(cs.Equals("bt0")) { // If button (bt0) clicked: // var's used: elevation_s (user selected) can be "up" or "down" // phrase_s (User selected) cs="rb0*";wm("gu"); // Get update for Radio Button grp if (cui==0) os="up"; else os="down"; // Store elevation selected by Radio ks="elevation_s";wm("vs"); // Buttons into a session var. cs="tf0";wm("gu"); // Get tf0 update, store it into ks="phrase_s";os=cus;wm("vs"); // the session var "phrase_s" } //------------------------------------ bt1 Click ------------------------------------- if(cs.Equals("bt1")) { // If button (bt1) clicked: cs="ch1";wm("gu"); // Get ch1's update, translate it into os=" RGP LGP SER SED ".Substring(4*cui,3); // a string which is an abriviation ks="effect_s";wm("vs"); // of item selected. Save the string. } } } CLASS elevation: ---------------- public partial class elevation:pasp { public override void init() { base.init(); } public override void update() { //--------------------------- Painting background --------------------------------- if(!cs.Equals("pl")) return; // Return if not Page_Load event lf=370;of=100;wm("bo"); // Open new bitmap operation using // bitmap of size 370 X 100 pixels cls="s4";gm("ec"); // Erase, paint with light gray fns="trb36"; // Set font to TimesRoman, bold, 36 ks="phrase_s";wm("vg");xs=os; // Get user's phrase, assign to (xs) if (xs.Length<1) xs="Personal C Sharp"; // If var lost or corrupted use def ks="elevation_s";wm("vg"); // Get elevation selection (in os) if (os.Length<1) os="up"; // If var lost or corrupted use def //--------------------------- "Elevated up" String --------------------------------- if (os.Equals("up")) { y=0; // (y) = Page center vertically. cls="s9";gm("sps"); // Set color to white os=xs;kf=y+2;gm("ctf"); // Draw text slightly above (y) cls="S9";gm("sps"); // Set color to black os=xs;kf=y-2;gm("ctf"); // Draw text slightly under (y) cls="s4";gm("sps"); // Set color to wanted color os=xs;kf=y;gm("ctf"); // Draw text exactly at (y) } //--------------------------- "Elevated down" String -------------------------------- else { y=0; // (y) = Page center vertically. cls="S9";gm("sps"); // Set color to black os=xs;kf=y+2;gm("ctf"); // Draw text slightly above (y) cls="s9";gm("sps"); // Set color to white os=xs;kf=y-2;gm("ctf"); // Draw text slightly under (y) cls="s4";gm("sps"); // Set color to wanted foreground color os=xs;kf=y;gm("ctf"); // Draw text exactly at (y) } wm("bc"); // Close bitmap operation. } } CLASS effects: -------------- public partial class effects : pasp { public override void init() { base.init(); } public override void update() { if(!cs.Equals("pl")) return; // Return if not Page_Load event lf=of=185;wm("bo"); // Open new bitmap operation using // bitmap of size 185 X 185 pixels cls="p7";gm("ec"); // Paint background same as page lf=of=150;gm("ce"); // Create a circle ks="effect_s";wm("vg"); // Retrieve the effects string if (os.Length<1) os=" "; // If var lost or corrupted use default //----------------------------- Radial Gradient Paint ------------------------------ if (os.Equals("RGP")) { // If "Radial Gradient Paint selected: cls="s9g0";gm("spr"); // Make radial gradient brush for the circle gm("grf"); // Render-fill the circle object. } //----------------------------- Linear Gradient Paint ------------------------------ else if (os.Equals("LGP")) { // If "Linear Gradient Paint selected: cls="s9r0";ad=0;gm("spl"); // Make linear gradient brush for the circle gm("grf"); // Render-fill the circle object. } //-------------------------- Special Effects - Reflection --------------------------- else if (os.Equals("SER")) { // If "Sp Effects-Reflection selected: of=5;cls="b0";ks="r";gm("grs"); // Render with sp effects-reflection // brightness factor=5, blue color } //----------------------------- Special Effects - Depth ----------------------------- else if (os.Equals("SED")) { // If "Sp Effects-Depth selected: cls="s9s0";id=20;ad=30;ks="d";gm("grs"); // Render with sp effects-depth // Shear angle=30, Depth=20 pixels } //---------------------------- No 3D Effects Requested ------------------------------ else { // If No Selection made (title selected): cls="p0";gm("sps"); // Create Pink solid paint brush gm("grf"); // Render-fill the circle object. } wm("bc"); // Close bitmap operation. } } =========================================================================================


EXAMPLE 8: Since generating graphics dynamically in a web application is very important, we are going to turn more of the desktop drawing examples into web applications. Here are two more: (1) Drawing example number 7 which shows how to use the special effects-depth in your drawing. (2) Drawing example number 9 which shaws how to draw an arch or a circle of char's and how to use shadows in order to give your drawing the 3D effect. ========================================================================================= THE MAIN CLASS (class pg8) -------------------------- public partial class pg8:master1 { // Page class extends master class public override void init() { base.init(); } public override void setup() { base.setup(); // Run setup() of master page first //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 2 col, 2 rows cs="im1";cis="";j=0;k=0;i=2;ds="c";lf=370;of=100; // Image control where the drawing ims="depth.aspx";wm("i"); // will be, ims=the ".aspx file" cs="tf0";cis="Enter upto 7 chars word";j=0;k=1;ds="s"; jf=7;od=7;cls="b0y0";fns="trb12";wm("i"); // tf0 takes upto 7 chars only. cs="bt0";cis="Submit";j=1;k=1;ds="s"; // bt0 is the submit button. cls="r0g8";fns="trb12";wm("i"); //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 1 col, 1 row cs="im2";cis="";j=0;k=0;i=2;ds="c";lf=370;of=180; // Image control where the drawing ims="arch.aspx";wm("i"); // will be, ims=the ".aspx file" cs="tf1";cis="Enter upto 35 chars message";j=0;k=1;ds="s";jf=35;od=35; cls="b0y0";fns="trb12";wm("i"); // tf1 size takes upto 35 chars. cs="bt1";cis="Submit";j=1;k=1;ds="s"; // bt1 is the submit button. cls="r0g8";fns="trb12";wm("i"); } //------------------------------------------------------------------------------------ public override void update() { if(cs.Equals("pl")) { // If event is "Page_Load" setup(); // Execute setup() MakePage(table); // and Make the page if (!IsPostBack) { // If first trip to retrieve page: ks="text_s";os="FAMSOFT";wm("vs"); // Store default values into var's ks="message_s";os="Great Graphics With PC# and MS .NET";wm("vs"); } PageNumber(8); // Call master class's method } // to display this page's number if(cs.Equals("bt0")) { // If event is: "bt0 clicked" cs="tf0";wm("gu"); // Get update text of tf0 in (cus) ks="text_s";os=cus;wm("vs"); // and store it into its session var } if(cs.Equals("bt1")) { // If event is: "bt1 clicked" cs="tf1";wm("gu"); // Get update text of tf1 in (cus) ks="message_s";os=cus;wm("vs"); // and store it into its session var } } } CLASS depth: ------------ public partial class depth:pasp { public override void init() { base.init(); } public override void update() { if(!cs.Equals("pl")) return; lf=370;of=100;wm("bo"); // Open new bitmap operation using // bitmap of size 185 X 185 pixels cls="b2";gm("ec"); // Paint background blue. ks="text_s";wm("vg");xs=os; // Retrieve text from session var. if (xs.Length<1) xs="FAMSOFT"; // If var lost or corrupted use default fns="trb64";cls="s9s0"; // Set color (Brightest-Darkest) and font os=xs;gm("ct"); // Get Shape object for text id=8;ad=30;ks="d";gm("grs"); // Draw with depth=8, Shear angle=30 wm("bc"); // Close bitmap operation. } } CLASS arch: ----------- public partial class arch:pasp { public override void init() { base.init(); } public override void update() { //---------------------------- Painting background ---------------------------------- if(!cs.Equals("pl")) return; // Return if not Page_Load event lf=370;of=180;wm("bo"); // Open new bitmap operation cls="s9";gm("ec"); // Paint background white cls="s5";gm("sps"); // Set color to gray for(int i=-90;i<91;i+=4) { // Fill background area with a pattern kf=i;of=2;lf=370;gm("crf"); // of 2 pixels thick horizontal gray lines } //--------------------------- Prepare user's message -------------------------------- ks="message_s";wm("vg");xs=os; // Retrieve stored message. Assign it to (xs) if (xs.Length<1) xs="Great Graphics With PC# and MS .NET"; // If var lost or corrupted use default while(xs.Length<35) { // If message length was < 35, Keep adding xs+=" "+xs; // it to itself untill it becomes =>35. } xs=xs.Substring(0,35); // Trim message to 35 chars fns="crb24"; // Set font to courier, bold, size 24. //----------------------------- Draw Message's shadow -------------------------------- lf=370;of=370;gm("bn"); // Create 370 X 370 Bitmap. gm("sdb"); // Set output device to (bip) to draw on it. cls="S94";gm("sps"); // Set color to (40% opaque) black char[]XC=xs.ToCharArray(); for (x=0;x< xs.Length;x++) { // Scan arch string, assign its char's one by os=""+XC[x]; // one to (os) then create (gpp) representing gm("ct"); // the char. lf=150;of=175-5*x;kb=true; // Modify (utp) to xfrm char's to points of ad=90-5*x; // rad=150 and different angles starting at gm("stu"); // 175 and making an arch. gm("gtf"); // Xfrm & draw-fill (gpp) of each char. } gm("sdd"); // Return output device to its default setting jf=0;kf=-100;gm("br"); // Draw the bitmap with the shadow on. //------------------------------- Draw the Message ----------------------------------- lf=370;of=370;gm("bn"); // Create 370 X 370 Bitmap. gm("sdb"); // Set output device to (bip) to draw on it. cls="r0";gm("sps"); // Set color to pure red for (x=0;x< xs.Length;x++) { // Scan the string and draw it just as you os=""+XC[x]; // did with the shadow. gm("ct"); lf=150;of=175-5*x;kb=true; ad=90-5*x; gm("stu"); gm("gtf"); } gm("sdd"); // Return output device to its default setting. jf=0;kf=-93;gm("br"); // Draw the bitmap with the message on it // slightly above its shadow. wm("bc"); // Close bitmap operation. } } =========================================================================================


NETWORKING ========== Networking can also add a lot to your web applications. The demonstrative examples of the Networking section include several examples which can be used in web applications Here are some of them: (1) Obtaining the latest stock price of a company by connecting to CNN financial website and retrieving the page which contains the stock information, then searching the page and picking the stock price burried into its html text. (2) Checking received e-mail messages, reading received messages and sending messages programmatically. (3) Accessing ftp sites and downloading or uploading files programmatically. We are going to start with the first one. However, before we do it, we need to see how we can convert a simpler application example into a web application. That example is the one which has created the old fashion texetual Menu. It'll show you how to use a Literal control which includes text to display while changing font and color. In fact, you can insert a complete page of text into your web page using the same method. EXAMPLE 9: In the left section, duplicate example 4 of the General Demonstrative Examples section as a web application. In the right section modify example 1 of "Networking" so that it gets the stock price for any stock symbol the user selects and displays the price to the user. ========================================================================================= public partial class pg9:master1 { // Class extends master1 as uasual public override void init() { base.init(); // Initialize pasp } public override void setup() { base.setup(); // Execute setup() of master1 class //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 2 cols, 2 rows wm("o"); // Open a new html loading operation cls="r0"; // Set color to "Pure red". fns="trb14";ds="c"; // Set font to "times roman",bold,size 14. os=" MENU"; // and display this text. wm(); // Call method wm() to execute. cls="S9";fns="trb10";ds="w";wm("dp"); // Change color, font and direction os=" (R) Red.";wm(); // Display this line. os=" (B) Blue.";wm(); // and this line. os=" (G) Green.";wm(); // and this line os="";wm(); // skip one line cls="b0"; // Change Color. os="Selection :";wm(); // Display "Get selection" string wm("c"); // Close html operation cs="lt1";j=0;k=0;i=2;ds="w";cls="S9g7";fns="trb12";wm("i"); // Install the literal value whose label is // the text above. cs="tf0";j=0;k=1;jf=36;ds="sw";cls="b0y0";fns="trb12";wm("i"); cs="bt0";j=1;k=1;cis="OK";cls="r0g7";fns="trb12";ds="se";wm("i"); // Install text field and button. //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 1 col, 2 rows cs="tf1";cis="Stock Symbol";j=0;k=0;jf=20;ds="c";cls="b0y0";fns="trb12";wm("i"); cs="bt1";j=0;k=1;cis="Get Quote";cls="r0g7";fns="trb12";ds="c";wm("i"); } //----------------------------------------------------------------------------------- public override void update() { //------------------------------------ Page Load ------------------------------------ if(cs.Equals("pl")) { // If event is "Page_Load": setup(); // Execute setup() MakePage(table); // Make the page to be sent PageNumber(9); // Call master1 class's method to } // set page number. //------------------------------------ bt0 Click ------------------------------------- if(cs.Equals("bt0")) { // If button (bt0) clicked: cs="tf0";wm("gu"); // Get tf0's update (cus) if (cus.Length<1) cls="S9"; // If no text set color to black else { // else: os=cus.Substring(0,1); // Get first char of the string entered. om("u"); // Convert it to upper case c="RGB".IndexOf(os); // See if it means red, green or blue. cls="S9 r0 G2 b0 ".Substring(3*(c+1),2); } // Form the color code accordingly wm("o"); // Open a new html loading operation fns="trb12";os="Hello World";wm("d"); // Display the message. wm("c"); // Close the html operation cs="lb00";wm("sl"); // Set lb00's label after being loaded with // the html. cs="tf0";cus="";wm("su"); // Erase text into tf0. cs="tf0";wm("sx"); // Set focus at tf0. } //------------------------------------ bt1 Click ------------------------------------- if(cs.Equals("bt1")) { // If button (bt1) clicked: cs="tf1";wm("gu"); // Get tf1's update which is the stock symbol cus=cus.ToUpper(); //------ Get the page ------ urs="http://money.cnn.com/quote/quote.html?symb="+cus; jb=true;kb=true;nm("hg");tm(); //Get html file replacing {}<> with |'s //------ Pick data around the price ------ txs=os; // Assign file to search string (txs) js=":MSFT)";ks="As of";tm("s"); // Get the string between js & ks and assign it to (os) //------ Remove chars following the price ------ for(c=os.Length-1;c>-1;c--) { // Scan (os) char's backward. Stop at first numeric char if("0123456789.,".IndexOf(os.Substring(c,1))>-1) break; } os=os.Substring(0,c+1); // Remove all chars after that one from (os) //------ Remove chars before the price ------ for(c=os.Length-1;c>-1;c--) { // Scan (os) char's again. Stop at first char which if("0123456789.,".IndexOf(os.Substring(c,1))<0) break; } // is not a digit, decimal point or comma. os=os.Substring(c+1); // Remove all char's upto that one from (os) //------ Display stock price ------ cis="Latest stock price: $"+os; // Assign the stock price in (os) to the label cs="lb01";wm("sl"); // of lb01 then set the label. cs="tf1";cus="";wm("su"); // Erase tf1's text content cs="tf1";wm("sx"); // Set focus at tf1. } } } =========================================================================================


E-MAILING ========== Sending an e-mail message in full color programmatically: -------------------------------------------------------- The pc#'s networking method nm() can be used to programmatically check for new e-mail messages, read the messages and send new messages. The demonstrative examples on networking have shown how to do so. The code used in those examples can be used to send e-mail messages within your web page files with a great enhancement which is the ability to use HTML. This allows you to send an e-mail message in several colors and fonts, nice looking tables, images,...etc. We are going to modify example 3 of "Networking" which was used to send an e-mail message with a picture attachment which says: Dear Friend, My picture to you with love. This time we are going to include the picture into the message and going to make the first line of the message body show in red and the second line show in blue. You need to modify the lines identified with "****" with your actual data. ========================================================================================= public partial class SendMail:pasp { public override void init() { base.init(); } public override void update() { if(!cs.Equals("pl")) return; // Return if not PageLoad event wm("o"); // Open html loading operation js="..\\images\\flower.jpg";wm("fp"); // Get system path for image file ims=fls;ds="s";wm("di"); // Display picture wm("dp"); // Move to next paragraph cls="r0";fns="trb12"; // Chang color to red os="Dear Friend,";wm();wm(); // Display 1st msg body line, skip a line cls="b0"; // Change color to blue os="My picture to you with love.";wm();// Display 2nd msg body line wm("c"); // Close html loading operation OS[0]=cis; // Load entire msg body into OS[0] uhs="Your SMTP Server Name.com"; // *** Replace with your SMTP server address ids="Your User ID";pss="Your Password";// *** Replace with actual ID, Password js="YourID@YourHost.com"; // *** Sender E-Mail address ks="HerID@HerHost.com"; // *** Recipient E-Mail address os="My gift to you."; // Message Subject kb=true;nm("ms"); // Send the message using HTML body os="Message sent";wm("rw"); // Inform user using "Respose" object } } ========================================================================================= As you must know, you need to use the tool "pcw" to generate the "SendMail.aspx" file then run it with your browser. Getting a return e-mail message from the user: ---------------------------------------------- You can include links within your web pages which when clicked on by a user, the user's mailing software displays the "send mail" dialog with the "mail to" section filled in with the e-mail address which you supply. This feature is available with two controls, the "Literal Control" and the "Hyperlink Control". Here is how to install a Literal control which displays user's "send mail" dialog: wm("o"); // Open an html loading operation urs="YourID@yourhost.com"; // E-mail address to send message to os="Click here to send us a message"; // Phrase to click on wm("a"); // Create hyper link wm("c"); // Close html operation cs="lt0";wm("i"); // Create Literal Control whose (cis) // contains html necessary for the link. And here is how to install a Hyperlink Control to do the same: cs="hl0"; // Keyname of the Hyperlink Control cis="Click here to send us a message";// Phrase to click on urs="YourID@yourhost.com"; // E-mail address to send message to wm("i"); // Install the control ========================================================================================= REUSABLE DYNAMIC GRAPHIC GENERATORS =============== The use of master pages has simplified web page development by allowing us to write repeated code once only instead of including the same code into every page class which we write. Do we need to do the same with "Dynamic Graphics" classes? Imagine if you like to write several card gaming classes which require the drawing of all 52 Cards. Wouldn't it be nice if we can write one class which generates the 52 cards and allow all the gaming classes to use that class internally? I know you agree and we can do it exactly in the same manner with the same simplicity as we did with master pages. You write the master graphics class as normal, then instead of using the tool "pcw" to generate the "aspx" file, you use the tool "pcwm" to compile it and store the library file generated into the Bin subfolder of your application's folder. The master graphics class extends "pasp" and all your gaming classes extend the master graphics class. It's time for an example. We can't draw the entire 52 cards here, but you can. So we are going to create a master graphics class which draws only the "Ace of Diamonds" card which we have created before in one of the old examples and use it by two game classes. ========================================================================================= EXAMPLE 10: We are going to create the class "cards" which contains 3 methods. The first method draws the front side of the card, the second method draws the back side and the third method draws a card with a question mark indicating that the user should guess which side the card is going to appear on. We are also going to create two gaming classes which extend class "cards". One class will ask the user to bet on which side the card will appear on and the other class will display 3 cards on their back sides and ask the uer to guess which one of them is the ace. Finally, we'll create "pg10" class which will run the two gaming classes on its left and right sections as usual. ========================================================================================= CLASS cards: ------------ public partial class cards:pasp { // Class extends (pasp) //------------------------------ Card's Front side --------------------------------- public void CardFront() { // Card's front drawing method cls="s9";gm("sps"); // Prepare solid white paint pen lf=224;of=300;gm("crf"); // Draw card's face rectangle cls="r0";gm("sps"); // Set color to pure red, solid pen/brush fns="trp24"; // Set font:TimesRoman, plain size=24 os="A";jf=-92;kf=130;gm("ctf"); // Draw the text "A" at top left os="A";jf=92;kf=-130;ad=180;gm("ctf"); // Draw same rotated 180 degrees // at bottom right corner. lf=of=30;ad=45;gm("crf"); // Fill a 30X30 square at card's center // rotated 45 degrees. jf=-92;kf=110;lf=of=12;ad=45;gm("crf"); // Do same but smaller at top left corner jf=92;kf=-110;lf=of=12;ad=45;gm("crf"); // and at bottom right corner } //------------------------------ Card's Back side --------------------------------- public void CardBack() { // Card's back drawing method cls="s9";gm("sps"); // Prepare solid white paint pen lf=224;of=300;gm("crf"); // Draw card's body rectangle cls="r0";i=5;gm("sps"); // Set pen color to red, size=5, solid lf=209;of=285;gm("crd"); // Draw a rectangular frame. lf=199;of=275;gm("cr"); // Create inner rectangle without drawing cls="b0s9";ad=-90;gm("spl"); // Set color to linear gradient changing // from blue to white at an angle of 90 deg // covering (gpp)'s bounding area. gm("grf"); // Render (gpp) and fill with color JF=new float[]{0,-100,100,0}; // Create Gen Path with points defined in KF=new float[]{138,-138,-138,138}; // JF[],KF[], Point Count=4. Don't draw it. oi=4;gm("cp"); cls="b0s9";ad=90;gm("spl"); // Create linear gradient color covering the // new (gpp) object and changing colors at // opposite direction gm("grf"); // Render (gpp) and fill with color } //----------------------------- Card's side unknown -------------------------------- public void SideUnknown() { // Unknown Card's side drawing method i=3;cls="S9";gm("sps"); // Set pen color to black, size=3, solid lf=224;of=300;gm("crd"); // Draw card's body rectangle fns="trb96";os="?";gm("ctd"); // Draw a question mark on the card } } CLASS game1: ------------ public partial class game1:cards { // Class game1 extends (cards) public override void init() { base.init(); // Initialize internal classes } public override void update() { // Var's used: b=user's bet (1 or 0) or user's new game request code (2) // x=Randomly generated winning bet. At the end of the game, it's stored in // memory and its stored value is used to keep the last game played frozen // on the screen when user playes the other side's game. if(!cs.Equals("pl")) return; // If event is not "Page_Load", return lf=224;of=300;wm("bo"); // Open new bitmap operation using bitmap of // size 224 X 300 pixels. cls="p7";gm("ec"); // Paint background with same color as page ks="bet1_s";wm("vg"); // Get bet which was stored as session var if (os.Length<1) os="2"; // If not found assign it "2"(means new game) om("ti");b=o; // Convert to int and assign to (b) if (b==-1) { // If PostBack was for the other side's game, ks="last1_s";wm("vg"); // get previous winning bet from memory, if (os.Length<1) os="2"; // If not found assign it new game code. om("ti");x=o; // Convert it to int, assign it to (x) } else if(b<2) { // Else if bet was valid (=0 or 1) i=1;um("mr");x=o; // Get random number between (0:1), consider } // it the winning bet, assign it to (x) else x=-1 // If new game requested make x=-1. // At this point: b=current bet. x=current winning bet if user was playing this game // or previous winning bet if user was playing the other game. If new game is // requested x=-1. if (x==0) CardFront(); // if (x=0) display card's front side else if (x==1) CardBack(); // if (x=1) display card's back side else SideUnknown(); // if (x=-1) display Unknown side card if(b==x) { // If bet matches winning bet, cls="o0";gm("sps"); // Change color to orange. jf=kf=0;os="YOU WON!";fns="trb36";gm("ctf"); } // Show "YOU WON" message o=x;om("fi");ks="last1_s";wm("vs"); // Convert winning bet to string and save it wm("bc"); // Close bitmap operation } } CLASS game2: ------------ public partial class game2:cards { // Class extends (cards) public override void init() { base.init(); // Initialize pasp } public override void update() { if(!cs.Equals("pl")) return; // If event was not "Page_Load", return; lf=370;of=150;wm("bo"); // Open new bitmap operation using bitmap of // size 370 X 150 pixels. cls="p7";gm("ec"); // Paint background with same color as page lf=224;of=300;gm("bn"); // Create new bitmap object (bip) ks="bet2_s";wm("vg"); // Get bet from memory if (os.Length<1) os="3"; // If not found assign "new game" code to it om("ti");b=o; // Convert bet to int and assign it to (b) if (b==-1) { // If PostBack was for the other side's game, ks="last2_s";wm("vg"); // get previous winning bet from memory, if (os.Length<1) os="-1"; // If not found assign it new game code. om("ti");x=o; // Convert it to int, assign it to (x) } else if(b<3) { // Else if bet was valid (=0,1 or 2) i=2;um("mr");x=o; // Get random number between (0:2), consider } // it the winning bet, assign it to (x) else x=-1; // If new game requested make x=-1. // At this point: b=current bet. x=current winning bet if user was playing this game // or previous winning bet if user was playing the other game. If new game is // requested x=-1. for (n=0;n<3;n++) { // Do 3 times using values of n=(0,1 & 2): gm("sdb"); // Make (bip) the graphical device if (n==x) CardFront(); else CardBack();// If n=winning card, draw card face up // else draw it face down on (bip) gm("sdd"); // Return to default graphical device (bio) lf=-120+120*n;jd=kd=0.5;gm("stu"); // Set Affine Xform to render (bip) scaled gm("brt"); // to half and drawn at different locations } // depending on the value of (n) gm("sdd"); // After done, make sure bio is the g device if(b==x) { // If user's bet=winning bet: cls="y0";gm("sps"); // Switch to yellow color jf=kf=0;os="YOU WON!";fns="trb64";gm("ctf"); } // Display "YOU WON" message o=x;om("fi");ks="last2_s";wm("vs"); // convert (x) to string and save it. wm("bc"); // Close bitmap operation } } CLASS pg10: ----------- public partial class pg10:master1 { // Class extends master1 as uasual public override void init() { base.init(); // Initialize internal classes } public override void setup() { base.setup(); // Execute setup() of master1 class //----------------------------------- tb2 Contents ---------------------------------- cns="tb2"; // tb2 is made of 2 cols, 5 rows cs="bt0";j=0;k=0;lf=0;cis="New Game";cls="r0g7";fns="trb12";ds="w";wm("i"); cs="lb1";cis="Head or Tail?";j=0;k=1;lf=0;ds="w";cls="r0p7";fns="trb12";wm("i"); cs="rb00";cis="Face Up";j=0;k=2;ds="w";cls="b0p7";fns="trb12";wm("i"); cs="rb01";cis="Face Down";j=0;k=3;ds="w";cls="b0p7";fns="trb12";wm("i"); cs="bt1";j=0;k=4;lf=0;cis="Submit Bet";cls="r0g7";fns="trb12";ds="w";wm("i"); cs="im1";cis="";j=1;k=0;o=5;ds="c";lf=150;of=200; // Image control where the drawing ims="game1.aspx";wm("i"); // will be, ims=the ".aspx file" //----------------------------------- tb3 Contents ---------------------------------- cns="tb3"; // tb3 is made of 3 cols, 3 rows cs="bt2";j=0;k=0;lf=0;cis="New Game";cls="r0g7";fns="trb12";ds="c";wm("i"); cs="lb2";cis="Where Is The Ace?";j=1;k=0;lf=0;ds="c";cls="r0p7";fns="trb12";wm("i"); cs="bt3";j=2;k=0;lf=0;cis="Submit Bet";cls="r0g7";fns="trb12";ds="c";wm("i"); cs="rb10";cis="";j=0;k=1;ds="c";cls="r0p7";fns="trb12";wm("i"); cs="rb11";cis="";j=1;k=1;ds="c";cls="r0p7";fns="trb12";wm("i"); cs="rb12";cis="";j=2;k=1;ds="c";cls="r0p7";fns="trb12";wm("i"); cs="im2";cis="";j=0;k=2;i=3;ds="c";lf=360;of=150; // Image control where the drawing ims="game2.aspx";wm("i"); // will be, ims=the ".aspx file" } //----------------------------------------------------------------------------------- public override void update() { //------------------------------------ Page Load ------------------------------------ if(cs.Equals("pl")) { // If event is "Page_Load" setup(); // Execute setup() if(!IsPostBack) { // If first trip to retrieve page ks="bet1_s";os="2";wm("vs"); // Save default values for current ks="last1_s";os="-1";wm("vs"); // bets and previous winning bets ks="bet2_s";os="3";wm("vs"); // for both games as session var's. ks="last2_s";os="-1";wm("vs"); } MakePage(table); // Make the page to be sent PageNumber(10); // Call master1 class's method to } // set page number. //-------------------------- New Game button of game1 clicked ------------------------- if(cs.Equals("bt0")) { // If New Game button clicked: // var's used: bet1_s (user bet) can be ("0" or "1"), // bet1_s="2" means "new game", bet1_s=-1 means do nothing since other game is played ks="bet1_s";os="2";wm("vs"); // Assign 2 to bet1_s (new game cd) ks="bet2_s";os="-1";wm("vs"); // and (-1) to other game var bet2_s } //---------------------------- Submit button of gam1 clicked -------------------------- if(cs.Equals("bt1")) { // If submit button clicked: // var's used: bet1_s (user bet) can be ("0" or "1"), bet1_s="2" means "new game" cs="rb0*";wm("gu"); // Get update for Radio Button o=cui;om("fi"); // group (in cui), convert to string ks="bet1_s";wm("vs"); // and save it as bet1_s then ks="bet2_s";os="-1";wm("vs"); // assign -1 to other game var bet2_s } //-------------------------- New Game button of game2 clicked ------------------------- if(cs.Equals("bt2")) { // If New Game button clicked: // var's used: bet2_s (user bet) can be ("0","1" or "2"), bet2_s="3" means "new game" ks="bet2_s";os="3";wm("vs"); // Assign New Game code to bet2_s ks="bet1_s";os="-1";wm("vs"); // and (-1) to other game var bet1_s } //---------------------------- Submit button of gam2 clicked -------------------------- if(cs.Equals("bt3")) { // If submit button clicked: // var's used: bet2_s (user bet) can be ("0","1" or "2"), // bet2_s="3" means "new game", bet2_s=-1 means do nothing cs="rb1*";wm("gu"); // Get update for Radio Button group o=cui;om("fi"); // (in cui), convert to string ks="bet2_s";wm("vs"); // and save it as bet2_s then ks="bet1_s";os="-1";wm("vs"); // assign -1 to other game var bet1_s } } } ========================================================================================= TUTORIAL: The only part which deserves explanation is the section of each game's code which handles the problem caused by having two active games available in the same page. If the user was playing "game1" then switched to "game2", his last bet in "game1" which was stored as session variable will stay there. Each time the user clicks a button into game2, game1 could not be prevented from running. It will generate a randomly selected winning bet as usual and displays its card(s) accordingly. Additionally the winning bet will be compared with the last bet and the winning message may be displayed if a match was found. This is of course unacceptable. Whenever the user switches to a new game, he expects the original game's look to stay unchanged all the time until he returns back to it. So we needed a way to make that happens. Here is what we did: (1) We created a second session variable for each game and used it to store the last winning bet which sets how cards are displayed into the page. (2) In "pg10" file, whenever we receive events for game2, meaning that the user is playing game2, we assign (-1) to bet1 and vice versa. This means that we replace the last stored bet of the unused game with "no bet" code value. (3) When the unused game runs, it reads its last bet and finds it equal to (=-1). This causes it to do things differently. Instead of using the random generator to obtain the winning bet, it reads its last stored winning bet and uses it to draw the cards on the screen. So the cards look stays the same all the time.