Saturday 15 December 2012

Start learing in MVVM ( silverlight or WPF Link)

OK, Lots of confusion around this pattern. I am also trying to wrap my head around this pattern and wanted to present what I have learned so far as well as my favorite links on the subject. I’m also working on a sample program that is from start-to-finish.
Model View ViewModel is usually called:
  • MVVM 
  • PresentationModel
  • or just the plain ViewModel
  1. It is just an architectural pattern for Silverlight of WPF.
  2. It is designed to allow Designers to focus on the user experience instead of the business logic
  3. It’s been around since 2005, but has just now taken off because of the success of WPF/Silverlight.
  4. UI Unit Testing
So what is it and why is it so scary for a beginner.

Model- A class file
View – Usually a user control
ViewModel – Another class file : Your user control will get its data from the ViewModel. Please see the image below:

image

Image taken from orbifold.net – please don’t sue me. =)

I am planning on creating an application that shows you how to build it from start/finish. If you can’t wait on mine, here is a silverlight MVVM app that contains a full project using the pattern. Stay tuned!

Articles for more information:

WPF Apps With The Model-View-ViewModel Design Pattern by Josh Smith.

Introduction to Model/View/ViewModel pattern for building WPF apps

Advanced MVVM Book (Cost $10 but was written by Josh Smith)

MVVM – It’s Not Kool-Aid*

Videos for more information about the pattern:

Hands-On Model-View-ViewModel (MVVM) for Silverlight and WPF –recommended to watch the one on SilverLight first.

MVVM, a WPF UI Design Pattern - Essential Edition

Libraries of classes useful when building applications based on the MVVM philosophy.

MVVM Foundation
MVVM Light Toolkit

Mistakes to Avoid as a Web Developer



For all web developers, it is extremely important to give the best service they possibly can in order to make sure things are done correctly. However, it sometimes becomes an often occurrence that developers will make the same mistakes and that could send the whole project off course and force you to take longer than needed. This off course means more money being spent and time being lost that could be used on other stages.


Certain mistakes are common for developers, whether they are freelance or working for a firm. Avoiding these mistakes can help save you, your company and your client time and money no matter which capacity you’re working in. Here are a few tips to avoid mistakes in order to be successful and increase your reputation in the web developing world.

Keep the Lines of Communication Open

One of the main problems that many developers experience is the inability to communicate with clients or the “higher-ups” in order to come together on wants and needs when planning the web development. Clients and firms don’t always have a full understanding on what you as a developer are capable of and what you can use. Help make things easier and clearer for the clients and yourself by giving an idea of what can be done and let them fill out the remaining information in order to make things go smoothly.

Understand the Size of Project

Research is such an important part of developing in terms of understanding exactly what you will need in order to complete any project you’re about to work on. This is the time to learn and inform clients or firms of budget, timeline and any other needs that you will have to have to complete the project with no problems. Giving the clients and firms a better idea will also keep them from having you make the next mistake.

It’s a Marathon, Not a Sprint

Clients and firms, of course, would love to have all of their projects done fast, but that could come at the expense of having everything done right. Do not allow the clients or firms to rush you through any stage of the project whether it is planning or the actual developing so that you can make sure everything is in working order when you’re done with the project. This is where coming up with a pre-planned strike and numbers (budget, time) comes in complete handy because those that are expecting your projects won’t apply unrealistic numbers on you.

Know your Role

As a web developer, it is crucial that you understand that you are exactly that; a web developer. You are not a project manager, nor do you hold any other position. Your job is to develop and taking on any other responsibilities past that could result in you losing track of what you’re main objective is, causing a problem with your time and budget constraints.

Test, Test, Test

One of the biggest mistakes is for web developers to push the project without running multiple tests on multiple platforms and doing so alone. Different browsers, PCs, Mac computers, mobile; these are all different platforms to test on and enlisting some help will speed up the process and have a multiple set of eyes on everything just in case you miss something.
Be sure to use these tips when starting any project to avoid delays and make sure these mistakes don’t creep up on you.

JavaScript Mistakes You Must Avoid

If you are new to JavaScript and you write raw JavaScript or use any framework (jQuery, Mootools, Dojo, YUI) with it, you must avoid few mistakes. Actually these are my experiences when I was learning JavaScript.

Equality Operator

You may know that in js, two operators are used for comparing values. First is == (two equal signs). This operator compare the values but it doesn’t compare the data type of operands. For example if first operand is 1 and the second is true, the result will be true.
if( 1 == true ) {
    //this code will run
}
Here are more examples.
1 == "1"        //true
"true" == true  //false
1 == true       //true
"0" == 0        //true
"" == 0         //true
" " == 0        //true
"Str" == false  //false
"Str" == true   //false
 
Some of the results are unexpected specially for those who don’t know how JavaScript evaluates == operator. Actually every operand (no matter what data type it has) is converted to Number data type before comparison.

Consider the first example (1 == “1″). The first operand is already a number so no conversion occurs. Second operator is string so it’s converted or parsed to number. Now the second operator “1″ (string) is converted to 1 (number).

In the second example (“true” == true) is false because if the string contain characters other than digits, convertion to number will return NaN which means Not a Number. If anything is compared with NaN, comparison will always return false.

You can check what value will be returned after conversion to number using the Number constructor. Following are some tests in Firebug.

Number tests

Now you maybe wondering how === operator works. Equality operator (with 3 equal signs) in JavaScript compare not only the value of operands, but also the data type. If the data type of operands is different, it will always return false. Both the data type and value of operands must be same in order to make the condition true.

4 === 4         //true
"2" === 2       //false
1 === true       //false
"true" === true //false

Not Assigning null to Reference Types

It’s common mistake that many js developers don’t assign null value to variables of reference types (object or Array) when there use is finished. Take a look at following example.

var arr = [1, 2, 3];
 
//perform some processing on arr
 
//assign null to arr when its use is finished
arr = null;
 
The benefit of assigning null to reference types is that the garbage collector of js engine automatically reclaims the memory used by that variable. Remember that this is specially important for variables whose scope is large like global variables. Local variables are automatically destructed when they are out of scope (specially js engines with Mark and Sweep garbage collector).

Reference Variable Initialization

Never try to initialize multiple reference variables (like object and array) in a single assignment statement. This can be better understood using an example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var arr1 = [1, 2, 3]
  , arr2 = ['a', 'b', 'c'];
 
//reset both arrays
arr1 = arr2 = [];
 
//add a single item in arr2 and arr1
arr2.push( 32 );
arr1.push( 10 );
 
//print both arrays and you will see same result
//OUTPUT: 10, 32
alert( arr1.join() );
alert( arr2.join() );
 
On line 1 and 2, two arrays are created. Then those arrays are reinitialized with blank array in a single statement on line 5. The problem with this statement is that now both arrays (arr1, arr2) are pointing to same array in the memory. So changes in one will automatically be reflected in the other.

On line 8, integer 32 is added in arr2 and on line 9, integer 10 is added in arr1. To check the output of both arrays, join method is called on each of them on lines 13 and 14. Note that both arrays contain same values.

Don’t Forget Keyword var

In JavaScript you can declare variables with keyword var. But it also allows you to use variables without any declaration. There’s a very critical difference between these two ways of using variables. Consider the following example.

function createVar() {
	var myVar = 'local';
};
 
alert( myVar ); //output: undefined
 
As you can see from the above example when a variable is declared with keyword var, it’s not accessible in the outer scope. Let’s change this example to define a variable without var in function.
 
function createVar() {
	myVar = 'local';
};
 
alert( myVar ); //output: local

Note that a variable defined without keyword var in function is also accessible from the global scope. In other words var makes the variable local. So becareful when using variables in JavaScript. Always declare your variables using keyword var before using them.

Not Using Event Delegation

Attaching event handler is simple in JavaScript. For example following code adds a click handler to anchor tag having id myLink.

document.getElementById('myLink').addEventListener( 'click', function() {
   //you code goes here...
}, false );
 
Now suppose you want to add a click handler to all the td elements in table. Are you going to write a handler for each td in table?

<table id="myTable">
   <tbody>
      <tr>
         <td>1, 1</td>
	 <td>1, 2</td>
      </tr>
 
      <tr>
         <td>2, 1</td>
	 <td>2, 2</td>
      </tr>
   </tbody>
</table>
 
Here event delegates help us. In our case we will attach a single click event handler to myTable and within that we will check to see if a td element is clicked or not. In this way we don’t have to write and attach event handlers to every td in table. Such kind of handler is known as event delegate. Here’s the code for it.

document.getElementById( 'myTable' ).addEventListener( 'click', function( e ) {
      if( e.target && e.target.nodeName == 'TD' ) {
         console.log( e.target.innerHTML );
 
         //to access id
         //console.log( e.target.id );
 
         //to access className
         //console.log( e.target.className );
      }
   }, false );

innerText VS innerHTML

New js developers are often confused between innerHTML and innerText properties. Both innerHTML and innerText are used with element objects. innerHTML gets the html code inside the element and innerText gets the text inside the element.

innerHTML working

The dark gray background in Html is actually the output of innerHTML property. Note that the Html tags (in our case <p>) are also included in the output.
Let’s take a look at innerText example.

innerText working
As you can see from the above example that innerText gets the text inside the element (without html tags).

Adding Nodes in Bulk

It’s common in JavaScript to append list of nodes to some element in DOM. For example you may want to append a list of names to ul received from server using Ajax call. One way of doing this is shown below.

window.onload = function() {
//ul element - <ul id="list"></ul>
var list = document.getElementById( 'list' );
 
var item = null;
 
//suppose this json is returned from ajax call
var ajaxResponse = [
    { 'name' : 'Haiku' },
    { 'name' : 'Linux' },
    { 'name' : 'OS X' },
    { 'name' : 'Windows' }
];
 
//add all names in ajaxReponse to documentFragment
for( var i in ajaxResponse ) {
    item = document.createElement( 'li' );
    item.appendChild( document.createTextNode( ajaxResponse[ i ].name ) );
    list.appendChild( item );
}
} //end onload
 
/*
..:: OUTPUT ::..
<ul id="list">
<li>Haiku</li>
<li>Linux</li>
<li>OS X</li>
<li>Windows</li>
</ul>
*/

The problem with this method is that each time the item is appended to list in "for in" loop, the DOM gets updated immediately. This hurts performance because DOM manipulation is costly process.

“DocumentFragment is light weight version of document and it has no visual representation on the web page.”
The same output can be achieved using DocumentFragment. DocumentFragment is light weight version of document and it has no visual representation on the web page. Following is the example to append list items using DocumentFragment.

window.onload = function() {
    //create DocumentFragment
    var documentFragment = document.createDocumentFragment();
 
    var list = document.getElementById( 'list' ); //<ul id="list"></ul>
    var item = null;
 
    //suppose this json is returned from ajax call
    var ajaxResponse = [
	{ 'name' : 'Haiku' },
	{ 'name' : 'Linux' },
	{ 'name' : 'OS X' },
	{ 'name' : 'Windows' }
    ];
 
    //add all names in ajaxReponse to documentFragment
    for( var i in ajaxResponse ) {
	item = document.createElement( 'li' );
	item.appendChild( document.createTextNode( ajaxResponse[ i ].name ) );
	documentFragment.appendChild( item );
    }
 
    //append all items in documentFragment to list
    list.appendChild( documentFragment );
}

DOM Manipulation using innerHTML

Never use arithmetic assignment operator (+=) with innerHTML to add new markup. Whenever you change innerHTML, DOM updation occurs (Browser redraws the markup). So adding new markup using += operator (specially in a loop) decreases performance.
var container = document.getElementById( 'container' );
 
for( var i = 1; i <= 10; ++i ) {
    container.innerHTML += 'Item ' + i + '<br />';
}
Always use a temporary variable to store the markup you want to assign to innerHTML as shown below.
var container = document.getElementById( 'container' )
  , str = '';
 
for( var i = 1; i <= 10; ++i ) {
    str += 'Item ' + i + '<br />';
}
 
container.innerHTML += str;

Sunday 9 December 2012

Data View & Data Source Controls in Asp Net

Goals:
  • Present data source and data view controls.
Prerequisites:
  • The Northwind database installed in SQL Server instance. [Northwind's script]
Steps:
  1. Create a new ASP.NET Web Application project in Visual Studio.
  2. There are two types of server controls participate in the declarative data binding model:
    • Data source controls:
      • They do not render any user interface.
      • They act as an intermediary between a particular data store and other controls on the ASP.NET Web page.
      • They enable rich capabilities for retrieving and modifying data, including querying, sorting, paging, filtering, updating, deleting, and inserting.
      • Depending of the source of the data, one of the following controls can be used:
        • SqlDataSource - for any SQL database; it returns data as DataReader or DataSet objects
        • AccessDataSource - specialized version of the SqlDataSource control - only for Microsoft Access
        • LinqDataSource - for LINQ to SQL
        • EntityDataSource (3.5 SP1) - for Entity Framework
        • XmlDataSource - for data stored in XML files
        • SiteMapDataSource - special data source for a definition of web site's structure; used by navigational controls
        • ObjectDataSource - for special, custom logic of loading data (e.g. from services)
    • Data bound (data view) controls:
      • Controls designed to display bound data:
        • DetailsView
        • FormView
        • DataList
        • ListView
        • DataPager (it does not display the data, but allows to add paging for e.g. a ListView control)
      • Other controls that can be used to display bound data:
        • GridView
        • Repeater
  3. SqlDataSource
    • Add a SqlDataSource to the page.
    • Choose the 'Configure Data Source' task (available at the small button attached to the control in the Design mode). Choose the Northwind database and than the Customers table. We will allow the user to modify the displayed data, so using the Advanced button set the option of generating insert, update, and delete commands also:
    • The following markup code is generated:
      <asp:SqlDataSource ID="SqlDataSource1" runat="server"
          
      ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
          
      DeleteCommand="DELETE FROM [Customers] WHERE [CustomerID] = @CustomerID"
          
      InsertCommand="INSERT INTO [Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax]) VALUES (@CustomerID, @CompanyName, @ContactName, @ContactTitle, @Address, @City, @Region, @PostalCode, @Country, @Phone, @Fax)"
          
      SelectCommand="SELECT * FROM [Customers]"
          
      UpdateCommand="UPDATE [Customers] SET [CompanyName] = @CompanyName, [ContactName] = @ContactName, [ContactTitle] = @ContactTitle, [Address] = @Address, [City] = @City, [Region] = @Region, [PostalCode] = @PostalCode, [Country] = @Country, [Phone] = @Phone, [Fax] = @Fax WHERE [CustomerID] = @CustomerID">    <DeleteParameters>
              <asp:Parameter Name="CustomerID" Type="String" />     </DeleteParameters>
          <UpdateParameters>
              <asp:Parameter Name="CompanyName" Type="String" />         <asp:Parameter Name="ContactName" Type="String" />         <asp:Parameter Name="ContactTitle" Type="String" />         <asp:Parameter Name="Address" Type="String" />         <asp:Parameter Name="City" Type="String" />         <asp:Parameter Name="Region" Type="String" />         <asp:Parameter Name="PostalCode" Type="String" />         <asp:Parameter Name="Country" Type="String" />         <asp:Parameter Name="Phone" Type="String" />         <asp:Parameter Name="Fax" Type="String" />         <asp:Parameter Name="CustomerID" Type="String" />     </UpdateParameters>
          <InsertParameters>
              <asp:Parameter Name="CustomerID" Type="String" />         <asp:Parameter Name="CompanyName" Type="String" />         <asp:Parameter Name="ContactName" Type="String" />         <asp:Parameter Name="ContactTitle" Type="String" />         <asp:Parameter Name="Address" Type="String" />         <asp:Parameter Name="City" Type="String" />         <asp:Parameter Name="Region" Type="String" />         <asp:Parameter Name="PostalCode" Type="String" />         <asp:Parameter Name="Country" Type="String" />         <asp:Parameter Name="Phone" Type="String" />         <asp:Parameter Name="Fax" Type="String" />     </InsertParameters>
      </
      asp:SqlDataSource>
      Note that using the SqlDataSource control allows to create a web database application in seconds, but the generated code is quite hard to maintain - there are no data access and data logic layers, everything is mixed in the presentation layer.
  4. GridView
    • Add a GridView control to the page. As the DataSourceID, set the SqlDataSource1 control. Note that columns are automatically generated. Select also all checkboxes on the GridView Tasks window to enable additional options:
    • Run the page and note how easy was to create quite functional grid for presenting data for modification:
    • After a few more seconds and clicks (auto format, font, alignment of the pager), the page can change its appearance radically:
  5. LinqDataSource
    • Add a new 'LINQ to SQL Classes' item to the project:
    • Add all tables of the Northwind database to the new created DataClasses1.dbml file (drag them from the Server Explorer window):
    • Add a new page (i.e. a Web Form item) to the project.
    • Add a new LinqDataSource control to the page. Configure it using the 'Configure Data Source' task:

      (If the list of available context objects is empty, compile the project and try again.)
    • As in the previous example, we will allow the user to modify data:
    • We have chosen the Customers table, so name the control customersLinqDataSource.
    • Add another LinqDataSource named ordersLinqDataSource attached to the Orders table:
  6. DetailsView
    • Add a DetailsView control to the page. Set its DataSourceID to customersLinqDataSource and enable some additional features:
    • Run the page and check its functionality:
    • Let's display all orders of the selected customer at the right side using a grid:
      • Create a Table with 2 cells, put the DetailsView control to the left cell and the GridView control to the right one:
      • Set the ordersLinqDataSource control for the DataSourceID property of the GridView.
      • Run the page and note that data in the GridView is not filtered for the customer selected in the DetailsView control:
      • There is no need to write code to set the proper filter for the grid, it is enough to configure the ordersLinqDataSource control using the Visual Designer:
      • Make some cosmetic changes in the appearance of both visible controls and enjoy the result:
  7. FormView
    • The next step to improve our web application is to create a page that displays details of an order in a nice and easy to modify way.
    • Add a new page to the project, name it order.aspx.
    • Add a LinqDataSource control:
      • Name it orderLinqDataSource.
      • Configure it to get data from the Orders table of the DataClasses1 source. Be sure to enable modifying the data:
      • We want to display a single order, so we should filter the data source. As a filtering parameter we use OrderID which will be passed to the page in the query string:

        Be sure to set the default value for the parameter taken from the QueryString. Without this default value, the LinqDataSource control would try force converting nothing to an integer value and as a result the user would see an exception displayed on the page.
    • Add a FormView control to the page, set the DataSourceID property to orderLinqDataSource:
    • In most of data view controls, it is possible to define what should be displayed if there is no data. For the FormView control, it can be done by defining the EmptyDataTemplate:
    • Run the page:
    • If there is a proper OrderID parameter in the query string, the page displays data of the order:
    • To allow the user to jump directly to the order's details from the list of orders, set the Enable Selection options of the GridView control presenting orders to true:

      and add a handler for the SelectedIndexChanged event of the grid:
      protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
      {
          Server.Transfer(
      "~/order.aspx?OrderID=" + (int)GridView1.SelectedValue);
      }
      Note that transferring a request using the Server.Transfer method has some disadvantages. The better way would be adding a special column to the GridView control with manually created hyperlinks.
  8. ObjectDataSource
    • The last taks of this tutorial is to create a page displaying short information about customers in a form of a pageable list. Displayed information should contain: CustomerID, CompanyName, and number of orders.
    • Add to the project a class that will serve data (it will be used by the ObjectDataSource):
      using System;using System.Linq;using System.Data.Linq;using System.Collections;
      namespace DataControls
      {
          
      public class CustomersShortInfo     {
              
      private static DataClasses1DataContext customersDC;
              
      protected static DataClasses1DataContext CustomersDC
              {
                  
      get
                  {
                      
      if (customersDC == null)
                      {
                          customersDC =
      new DataClasses1DataContext();
                      }
                      
      return customersDC;
                  }
              }

              
      public static int GetCount()
              {
                  
      return CustomersDC.Customers.Count();
              }

              
      public static IEnumerable GetData(int startRowIndex, int maximumRows)
              {
                  
      var data =
                      (
      from c in CustomersDC.Customers
                      
      select new                  {
                           c.CustomerID,
                           c.CompanyName,
                           NumberOrders = c.Orders.Count
                       }
                      ).Skip(startRowIndex).Take(maximumRows);
                  
      return data;
              }
          }
      }
    • Add an ObjectDataSource control to the page. Configure it to use the GetData method of the CustomersShortInfo class to get data:
    • Modify the generated markup code to get such code:
      <asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
          
      TypeName="DataControls.CustomersShortInfo"
          
      EnablePaging="True"
          
      SelectMethod="GetData" SelectCountMethod="GetCount">
      </
      asp:ObjectDataSource>
      (Parameters of the GetData method are used automatically when paging is enabled, explicit declaration would cause problems.)
  9. ListView
    • Add a ListView control to the page.

      If there is no such control on the Toolbox, do not worry, just start typing '<asp:ListView' in the Source view of the page.
    • To make it work, the LayoutTemplate and ItemTemplate of the ListView control must be set. Additionally, because we expect paging parameters in the GetData method, a DataPager control must be used:
      <asp:ListView ID="ListView1" runat="server" DataSourceID="ObjectDataSource1">
          <LayoutTemplate>
              <div runat="server" id="lstProducts">
                  <div runat="server" id="itemPlaceholder" />         </div>
              <asp:DataPager ID="DataPager1" runat="server" PageSize="5">
                  <Fields>
                      <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True" />             </Fields>
              </asp:DataPager>
          </LayoutTemplate>
          <ItemTemplate>
              <div >             ID: <asp:Label ID="Label1" runat="server" Text='<%# Eval("CustomerID")%>' /><br />             Company name: <asp:Label ID="Label2" runat="server" Text='<%# Eval("CompanyName")%>' /><br />             Number of orders: <asp:Label ID="Label3" runat="server" Text='<%# Eval("NumberOrders")%>' />         </div>
              <br />     </ItemTemplate>
      </
      asp:ListView>
    • Run the page:
    • The appearance of data can be almost freely modified, e.g.:

       
      <asp:ListView ID="ListView2" runat="server" DataSourceID="ObjectDataSource1">
          <LayoutTemplate>
              <asp:DataPager ID="DataPager1" runat="server" PageSize="20">
                  <Fields>
                      <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True" />             </Fields>
              </asp:DataPager>
              <br />         <div runat="server" id="lstProducts">
                  <span runat="server" id="itemPlaceholder"/>
              </div>
          </LayoutTemplate>
          <ItemTemplate>
              <div style="float: left; width: 200px; margin: 20px 20px 20px 20px;">
                  ID: <asp:Label ID="Label1" runat="server" Text='<%# Eval("CustomerID")%>' /><br />             Company name: <asp:Label ID="Label2" runat="server" Text='<%# Eval("CompanyName")%>' /><br />             Number of orders: <asp:Label ID="Label3" runat="server" Text='<%# Eval("NumberOrders")%>' />         </div>
          </ItemTemplate>
      </
      asp:ListView>
[Source code]

Validation ASP.NET Server Controls

Goals:
  • Present ASP.NET validation controls.
Steps:
  1. Create a new ASP.NET Web Application project in Visual Studio.
  2. Add a Button and a Literal to the page:
    <asp:Button ID="PostbackButton" runat="server" onclick="PostbackButton_Click"
        
    Text="PostbackButton" />
    <
    asp:Literal ID="statusLiteral" runat="server"></asp:Literal>
    Add also code for the PostbackButton_Click method:
    protected void PostbackButton_Click(object sender, EventArgs e)
    {
        statusLiteral.Text =
    "PostbackButton_Click called";
    }
  3. RequiredFieldValidator
    • Add a TextBox control. Add also a RequiredFieldValidator control (from the Validation group in the Toolbox window) attached to this TextBox (using the ControlToValidate property):

      Run the page and note that the validator is hidden initially. It is visible only in case of a try to postback the page with empty value in the TextBox.
      Note also that the red error information displayed by the validator appears immediately. It is done by the JavaScript code used by the validator internally. All built-in validators have both the JavaScript and C# code for validating values provided by the user on the client and server-side, respectively.
    • The RequiredFieldValidator control works also for other types of controls, e.g. for the DropDownList:

      In this case, the InitialValue property of the RequiredFieldValidator control is the most important - it allows to point the default value which should be treated as non-value.
    • Add 2 additional TextBox controls with RequiredFieldValidator controls, but this time in one line, to see an effect of changing value of the Display property of the validator control.

      Run the page once with Static value for the Display property of the validator and once with Dynamic value. Note the difference in placing controls.
  4. ValidationSummary
    • This control is not a validator but a place for displaying all messages coming from validator controls.
    • It uses the ErrorMessage properties of all validator controls. To see it in action, set the Text properties of all used validators to 'Text of [#]' and ErrorMessage to 'ErrorMessage of [#]':
    • Add the ValidationSummary control under the button:
    • See the ValidationSummary control in action:
    • Make some tests - set or delete value either the ErrorMessage or the Text property. Try also to set the Display property to None.
    • Note also other interesting properties of the ValidationSummary control: DisplayMode, ShowMessageBox, and ShowSummary.
  5. Validators can be grouped by values of the ValidationGroup property. This property can be set for validator controls and all controls that can cause validation, in particular Button controls..
    • Modify the ValidationGroup property to value 'ValGroup1' for all existing validators, the ValidationSummary control, and the button.
    • Run the application and verify that there are no changes.
  6. CompareValidator
    • A classic need for a web application is to ask the user for a password and its confirmation:
      • When values of 2 controls should be compared, the ControlToValidate and ControlToCompare properties must be set.
      • Note that the 2nd button and this CompareValidator have the same value for the ValidationGroup property. Because the name is different than the corresponding value for controls from the first group, this group works independently.
      • Note also that when no password is written, the validator does not work. Use a RequiredFieldValidator control to require the user to enter data in the input control.
    • The CompareValidator control can also be used to check type of a value provided by the user. For example, to force the user to write a proper number:
      • In this case the Type and Operator properties are crucial.
      • Note also usage of the SetFocusOnError property.
    • Not only a type but also a value can be validated:
  7. RangeValidator
    • This control is similar to the CompareValidator control. As an example, ask the user for time:
  8. RegularExpressionValidator
    • This control can be very useful when there is a need to test if the user's input matches a string template. For example, check if the user has written a proper email address:
  9. CustomValidator
    • The CustomValidator control allows to provide a custom validation function in JavaScript and a method in C#. As an example, create a validator that will accept only numbers that can be devided by 5.
    • Add a CustomValidator control, Button, and TextBox. Be sure to set the ValidationGroup property:
    • The logic of the client-side and server-side validation is quite simple. The server-side validation is required to ensure that data provided by the user is correct. The client-side validation is desired to give the user an immediate feedback without waiting for the server's response.
    • The server-side validation must be written as a C# event handler for the ServerValidate event of the CustomValidator:
      protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
      {
          
      int num;
          
      if (int.TryParse(args.Value, out num) && num % 5 == 0)
          {
              args.IsValid =
      true;
          }
          
      else     {
              args.IsValid =
      false;
          }
      }
    • The client-side validation must be a JavaScript function:
      <script language="JavaScript">
          function
      CustomValidator1_ClientValidate(oSrc, args) {
              args.IsValid = (args.Value % 5 == 0);
          }
      </script>
      and the markup for the CustomValidator:
      <asp:CustomValidator ID="CustomValidator1" runat="server"
          
      ControlToValidate="TextBox11" ErrorMessage="Wrong!"
          
      onservervalidate="CustomValidator1_ServerValidate"
          
      ClientValidationFunction="CustomValidator1_ClientValidate"
          ValidationGroup="ValGroup4">
      </
      asp:CustomValidator>
  10. The text displayed by a validator control can use HTML tags. This feature allows to use in example image to notify the user about an error:

    using the following code:
    <asp:CustomValidator ID="CustomValidator1" runat="server"
       
    ControlToValidate="TextBox11" Display="Dynamic"
       
    ErrorMessage="<img src='exclamation.png' />"
       
    onservervalidate="CustomValidator1_ServerValidate"
       
    ClientValidationFunction="CustomValidator1_ClientValidate"
       
    ValidationGroup="ValGroup4">
[Source code]