Thursday, July 9, 2009

Lambda Expressions – Features of C# 3.0 (Part – 6)

In my earlier article we have seen the following new features of C# 3.0.

In this blog we will try to understand the concept of Lambda expressions.

What is Lambda Expression?

Lambda expressions are nothing but anonymous functions. Lambda expressions can be used to write expressions or statements. To write Lambda expression one has to make use of the Lambda operator which is read as “goes to”. Lambda operator is represented as “=>” i.e. an equal to sign followed by a greater than symbol. Lambda expressions normally have input parameters on the left side of the Lambda operator and expressions/statements on the right side. The lambda operator is used to separate the input arguments on the left side from the expression/statements on the right side. Lambda expressions are extensively used in LINQ. An e.g. of Lambda expression is given below.

public class LambdaExpressionDemo
{
    delegate int Add(int a, int b);
    public void PrintAddResult(int num1, int num2)
    {
        Add addResult = (a, b) => a + b;
        Console.WriteLine(addResult(num1, num2).ToString());
    }

    public double CountEmp()
    {
         System.Collections.Generic.List<Person> perColl = new List<Person>{
             new Person {FName="first", LName="lastFirs", Age=30},
             new Person{FName="second", LName="lastSecond", Age=24},
             new Person{FName="third", LName="Third", Age=44}};
            double avgAge = perColl.Count(p => p.LName.StartsWith("la")); 
         return avgAge;
     }   
}

In the above code one can see we have declared a delegate which returns an integer value and takes two integers as input parameters. Also you can see I have declared a delegate variable (addResult) and assigned an anonymous function using our Lambda expression. One thing to note here is that there is no need to declare the type of the input arguments for the anonymous functions. The compiler will infer the type. What the above lambda expressions means is that we have an anonymous function with two input parameters (left side of the Lambda operators are input parameters) which needs to be added and the result returned. Don’t you thing this is a very simple way of declaring a function. In the second e.g. I have made use of Lambda expression along with Count method. The lambda expression evaluates and checks whether the person’ LName starts with “la” and returns true or false. If it returns true then that record is counted. So the count will be 2.

To better understand the advantages/usefullness of Lambda expression we need to know how we use to implement these things in the earlier versions of C#. Lets see how we would do this in C# 2.0 using anonymous methods.

delegate int Add(int a, int b);
public void PrintAddResult(int num1, int num2)
{
    //Using anonymous methods of C#2.0.
    Add addResult = delegate(int aa, int bb) { return aa + bb; };
    Console.WriteLine(addResult(num1, num2));
}

In the above e.g. we are making use of Anonymous method feature of C# 2.0 where we are making use of delegates to declare an Anonymous methods (highlighted in green). Wherever you thing creating a method is redundant or will create overhead you can go ahead and make use of Anonymous methods. Also one can use anonymous methods in cases where a method or property or constructor expects a delegate. In the above code we have declared a delegate with the signature of the method and then again using delegate variable, addResult, we are declaring an Anonymous method. One can write any number of statements inside Anonymous methods. The scope of the variables declared in Anonymous methods are within the limits of Anonymous methods.

Now lets see how we would have done this in the good olden days of C#1.0.

delegate int Add(int a, int b);
public void PrintAddResult(int num1, int num2)
{
    //The good olden days of C#1.0
    Add additionDel = Addition;
}

public int Addition(int a, int b)
{
    return a + b;
}

In the above code you can see the good olden days of delegate declaration where one has to create a method (Addition) and then create a delegate (Add) representing the method. Once you have declared the delegate one can assign the method. So after seeing the olden ways of declaring the same functionality which can be achieved using Lambda expression one can see the advantages.

One can define two types of lambda, an Expression Lambda and a Statement Lambda. Lets see what each one of it means.

Expression Lambda: Expression lambda is nothing but an expression on the right side of the Lambda Operator. E.g are given below.

(a, b) =>  (a + b);
(int a, int b) => a > b;

An expressions is any piece of code which can be evaluated to a single value, object etc. So the above code are just e.g. of expressions, even an assignment of a value to a variable is also an expression.

Statement Lambdas: As the name suggests statement lambdas are ones which can have more than one line of code/statement. In expression lambda you normally have only one line of statement which executes and produces the output in the form of a single value or object etc whereas in statement lambda we have more than one line of statements enclosed in a curly brace ({}).

delegate int Add(int a, int b);
public void StatementLambda(int operand1, int operan2)
{
    Add result = (a, b) =>
    {
        int c = a + b;
        Console.WriteLine(c.ToString());
        return c;
    };
    result(operand1, operan2);
}

In the above code you can see we have written some three lines of code and this is an e.g. of statement Lambda. There are no restriction to the number of lines of code that can be written in a Lambda expression. As a good practice it will be nice if you can restrict the number of lines between 2 and 3 lines.

Some points about Lambda expressions

  • Lambda expressions are anonymous functions.
  • No need to declare the types of the variables used in the input parameter of the Lambda expression. The types will be inferred by the compiler.
  • If there are situation when the compiler cannot infer the type of the variable used, in those kind of scenarios we can explicitly declare the types for the input parameters as shown below.

delegate int Add(int a, int b);
public void PrintAddResult(int num1, int num2)
{
    Add result = (int a, int b) => a + b;
    Console.WriteLine(result(num1, num2).ToString());
}

  • Variables declared in a Lambda expressions are scoped inside the Lambda blocks.
  • Lambda declaration should match the signature of the delegate i.e. the number of parameters and return type.
  • Parameter less Lambdas can also be declared just by having a empty parentheses as shown below.

delegate void Print();
public void ParameterLessLambda()
{
    Print print = () => Console.WriteLine("Parameter less lambda executed.");
    print();
}

  • You can pass Lambda expression where a delegate is expected. E.g. is shown below.

/*Lambda expression passed as an argument where delegate was expected.*/
System.Threading.Thread thh = new System.Threading.Thread(
   () => Console.WriteLine("hi"));

  • When you are making use of Lambda expressions behind the scene the compiler does the extra work of creating an anonymous function for the Lambda expression. Lets see with an e.g.: the code and generated IL are pasted below.

/*Class having a delegate and a Lambda expression.*/
class LambdaExpression
{
    delegate int Add(int operand1, int operand2);
    public void LambdaExp(int operan1, int operan2)
    {
        //Lambda expression.
        Add result = (a, b) => a + b;
        Console.WriteLine(result(operan1, operan2));
    }
}

/*Below is the MSIL generated for the above method. */
.method public hidebysig instance void LambdaExp(int32 operan1,
int32 operan2) cil managed
{
    .maxstack 3
    .locals init (
        [0] class
LambdaExpressions.LambdaExpression/Add result)
    L_0000: nop
    L_0001: ldsfld class
LambdaExpressions.LambdaExpression/Add
LambdaExpressions.LambdaExpression::CS$<>9__Cach
edAnonymousMethodDelegate1
    L_0006: brtrue.s L_001b
    L_0008: ldnull
    L_0009: ldftn int32
LambdaExpressions.LambdaExpression::<LambdaExp>b
__0(int32, int32)
    L_000f: newobj instance void
LambdaExpressions.LambdaExpression/Add::.ctor
(object, native int)
    L_0014: stsfld class LambdaExpressions.LambdaExpression/Add
LambdaExpressions.LambdaExpression::CS$<>9__Cach
edAnonymousMethodDelegate1
    L_0019: br.s L_001b
    L_001b: ldsfld class
LambdaExpressions.LambdaExpression/Add
LambdaExpressions.LambdaExpression::CS$<>9__Cach
edAnonymousMethodDelegate1
    L_0020: stloc.0
    L_0021: ldloc.0
    L_0022: ldarg.1
    L_0023: ldarg.2
    L_0024: callvirt instance int32
LambdaExpressions.LambdaExpression/Add::Invoke(i
nt32, int32)
    L_0029: call void [mscorlib]System.Console::WriteLine(int32)
    L_002e: nop
    L_002f: ret
}

/*C# code decompiled from MSIL using .NET Reflector*/
internal class LambdaExpression
{
    // Methods
    public void LambdaExp(int operan1, int operan2)
    {
        Add result = delegate (int a, int b) {
            return a + b;
        };
        Console.WriteLine(result(operan1, operan2));
    }

    // Nested Types
    private delegate int Add(int operand1, int operand2);
}

In the above pasted code you can see the MSIL generated is making use of AnonymousMethodDelegate i.e. the compiler is converting Lambda expressions into Anonymous functions. This is proven from the decompiled C# code from the MSIL pasted above.

As with other features of C# 3.0 Lambda expression is also a way of writing terse code where the compiler does the extra work of generating the extra codes. In my next  we will have a look at Language Integrated Query (LINQ) for which all these features were incorporated in C#. Till then write terse code and try to learn more.

Sandeep

Friday, July 3, 2009

Working with Modal Popup extender control.

This blog discusses about the ASP.NET AJAX ModalPopupExtender control. In this blog we will see how to use the ModalPopupExtender control, how to display/show/call the ASP.NET AJAX ModalPopupExtender control from javascript, showing/displaying/calling the modal popup from a hyper link control within the gridview control and finally some important javascript methods of the ASP.NET AJAX ModalPopupExtender control. So first lets see how to use the ModalPopupExtender control.

How to use the ASP.NET AJAX ModalPopupExtender control?

Drag and drop a ASP.NET button/LinkButton/ImageButton or any control to an aspx page. To add a ModalPopupExtender control, drag and drop the control from the toolbox or Select the any of the ASP.NET controls like (button/LinkButton/ImageButton or any other control) and click the button with a greater than symbol as shown below.

image

When you click the arrow you will get a menu with an “Add Extender” option as shown below.

image

Click the “Add Extender” menu option and select “ModalPopupExtender” from “Extender Wizard” popup. Once you have added the ModalPopupExtender control you need an ASP.NET panel control. This is because the ModalPopupExtender control will show the content of the Panel control as a popup. Add ASP.NET Panel control and the content which you want to display as popup into the ASP.NET Panel control. Sample code with all the above requirement is pasted below. Don’t forget to drag and drop the ScriptManager control to the page.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ModalPopup.aspx.cs" Inherits="ModalPopup" %> 
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head runat="server"> 
    <title>Modal Popup Demo</title> 
    <style> 
    .backgroundColor 
    { 
        background-color:Gray;    
        filter:alpha(opacity=25); 
    } 
    </style> 
</head> 
<body> 
    <form id="form1" runat="server"> 
    <div> 
        <asp:ScriptManager ID="ScriptManager1" runat="server"> 
        </asp:ScriptManager>        
        <asp:Button ID="popupBtn" runat="server" Text="Click to see the modal popup." /> 
        <asp:Panel ID="Panel1" runat="server" Style="display: none; padding:10px; border:1px; border-style:solid;" BackColor="#FF9933" Width="400px"> 
            <h3 style="text-align: center;" id="header">Modal Popup</h3> 
            <p>This is a Modal Popup extender control. You are seeing this because you have clicked the hyperlink button.</p> 
            <p style="text-align: center;"><asp:Button ID="closeBtn" runat="server" Text="Close" /></p>        
        </asp:Panel> 
        <cc1:ModalPopupExtender ID="ModalPopupExtender" runat="server" 
            TargetControlID="popupBtn" 
            PopupControlID="Panel1"              
            OkControlID="closeBtn" 
            BackgroundCssClass="backgroundColor" 
            DropShadow="true" 
            PopupDragHandleControlID="header"/> 
    </div> 
    </form> 
</body> 
</html>

From the above code one can see I have a ScriptManager, an asp:Button control, an asp:Panel control, some contents inside the panel control and then we have the ModalPopupExtender control. Normally when you attach an ASP.NET panel control to a ModalPopupExtender control it will become invisible in the HTML rendered to the browser and if due to some reason if the panel control is being displayed in the page then just set the "Style" property' “display” attribute to “none” as in the above e.g. Now when you click the button you will see a popup as shown below.

image

Now lets see how to configure the ModalPopupExtender control. The configuration is pretty simple, you need to set some properties and and you will have your Modal popup. The properties are as follows

TargetControlID: This property is the one which tells, on click of which control the popup should be displayed. In our e.g. we have given the TargetControlID as our button control. You can assign the ID of any ASP.NET controls like LinkButton, ImageButton, HyperLink, DropDownList, CheckBox, RadioButton etc. Even you can give a label’ id as the TargetControlID.

PopupControlID: The ID of the control to be displayed as a modal popup. In our e.g. we have given ASP.NET panel control’ ID. You can give any ASP.NET control’ ID. If for e.g if you give the ID of a textbox then the textbox alone will be popped up. Its not compulsory that you should provide a ASP.NET panel control.

OkControlID: The ID of the control which should act as an Ok button. Clicking of this control will dismiss the popup.

BackgroundCssClass: The name of the CSS class which needs to be applied to the background of the popup. One thing to note here is that if you don’t provide a CSS class then the modal popup will not function like a modal dialog i.e. One will be able to interact with the controls in the back of the popup control, so its imperative to provide a valid CSS class name value to the BackgroundCssClass property. In the above e.g. we have defined a CSS class called “backgroundColor” in the header section of the aspx page. Please note in the CSS class definition we have applied “filter” property to make the background transparent.

DropShadow: Accepts a boolean value which specifies whether the popup should have shadow. True will give a shadow and false will disable the shadow.

PopupDragHandleControlID: The ID of the control clicking on which the ModalPopupExtender can be dragged. The control should be enclosed in the control specified using PopupControlID i.e. in our case inside the ASP.NET panel control. If a particular control ID is set as the PopupDragHandlerControlID then one can click on that control and drag the ModalPopupExtender control. In the above e.g. we have set the ID of the “h3” control as PopupDragHandleControlID, clicking which the popup can be dragged.

CancelControlID: If you want a button to behave as a Cancel button provide the ID of the button. This button will cancel the popup.

Drag: This property takes a boolean value which when set decides whether the popup control can have the drag feature. A value of true means the popup extender control can be dragged around the screen whereas false will disable the drag.

RepositionMode: This property accepts four values. They are “None”, “RepositionOnWindowResize”, “RepositionOnWindowResizeAndScroll” and “RepositionOnWindowScroll”. The default value is “RepositionOnWindowResizeAndScroll”. Explanation of each values is given below.

RepositionOnWindowResize: Will reposition the popup when the window is resized.

RepositionOnWindowScroll: Will reposition the popup when the scroll bar is moved.

RepositionOnWindowResizeAndScroll: Will reposition the popup when you resize or when you move the scroll bar. Its a combination of both “RepositionOnWindowResize” and “RepositionOnWindowScroll”.

None: The popup will not be tinkered with. It will be shown in its original position irrespective of window resizing or scroll bar being moved.

DynamicServicePath: Link to a webservice/aspx page from where data or content needs to be retrieved and displayed in the popup extender control.

DynamicServiceMethod: The method name from which content needs to be retrieved. The method can be a webservice method or a method in your code behind file of your aspx file. If you leave the “DynamicServicePath” empty and provide DynamicServiceMethod name then the system will try to ping the same page’ and try to find a method. We will see an e.g. with web service shortly.

DynamicContextKey: The string value which will be passed as the parameter to the method specified in DynamicServiceMethod. One thing to note here is that the parameter should be named contextKey in the webservice/code behind.

X: The X coordinates for the popup control.

Y: The Y coordinates for the popup control.

Showing the content of a webservice (asmx) method in a ModalPopupExtender control.

Showing the output of a web method of a web service in a ModalPopupExtender control is also pretty simple. First you need to have a web service, if you don’t have one its very easy to create one in Visual Studio. Create a web service and add a method the output of which you want to display in a ModalPopupExtender conrol. Below I have pasted the code of my webservice.

using System;
using System.Collections; 
using System.Linq; 
using System.Web; 
using System.Web.Services; 
using System.Web.Services.Protocols; 
using System.Xml.Linq; 
 
[WebService(Namespace = "http://tempuri.org/")] 
/*The below attribute is needed so that the webservice can process calls from ASP.NET AJAX controls. Without the below attribute one may get the following error. "Web Service call failed: 500"*/ 
[System.Web.Script.Services.ScriptService] 
public class Service : System.Web.Services.WebService 
{ 
    public Service () 
    { 
    } 
    /*Method which will be called by the ModalPopupExtender control.*/ 
    [WebMethod] 
    public string HelloWorld() 
    { 
        return "<b>Hello World</b><br/>"; 
    } 
}

The above webservice is pretty simple. It has only one web method and the most famous of them all, the “HelloWorld” method. The method returns a HTML formatted “Hello World” string.
One thing to note while writing a web service whose methods can be called by the ASP.NET Ajax controls is that you need to add the “[System.Web.Script.Services.ScriptService]” attribute. If the before mentioned attribute is not added then you may get the below web service error.

Web Service call failed: 500

The mark up for the ModalPopupExtender control to display the webservice’ web method output is pasted below.

<!--Web service content display demo-->
<asp:Panel ID="webServicePanel" runat="server" Width="300px" Height="300" BackColor="Azure"> 
    <asp:Label ID="webServiceContentLbl" runat="server" Text="Label"></asp:Label> 
    <asp:Button ID="clsBtn" runat="server" Text="Button" /> 
</asp:Panel> 
<asp:Button ID="webServiceCall" runat="server" Text="Click to see the output of a webservice in a popup." /> 
<cc1:ModalPopupExtender ID="ModalPopupExtender1" runat="server" TargetControlID="webServiceCall" OkControlID="clsBtn" DynamicServicePath="Service.asmx" DynamicServiceMethod="HelloWorld"   DynamicControlID="webServiceContentLbl"  
  BackgroundCssClass="backgroundColor" PopupControlID="webServicePanel" DropShadow="true">        
</cc1:ModalPopupExtender>

The difference from our previous ModalPopupExtender control is that we have configured some extra properties related to webservice request. They are DynamicServicePath where we have given the url of the web service, DynamicServiceMethod takes the web method name and finally DynamicControlID takes the ID of the control in which the output of the web method should be displayed. We have given the ID of the label control inside the panel control as the DynamicControlID. The label control will display “Hello World” string in bold.
The ModalPopupExtender is capable of displaying the output from normal aspx pages as well. To display some content its not compulsory that you need to create a webservice. One can directly show the output of a method in a code behind file in a ModalPopupExtender. Lets see how to do that.
Displaying the content of a webpage (aspx) method in a ModalPopupExtender control.
Below is the code behind file content of the ASPX page. The code is pretty straight forward. It has a static method called HelloWorld which returns the same text as that of the webservice.


public partial class ModalPopup : System.Web.UI.Page
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
    } 
    /// <summary> 
    /// Page method which will be called by the modal popup extender control. 
    /// </summary> 
    /// <returns></returns> 
    [System.Web.Services.WebMethod(), System.Web.Script.Services.ScriptMethodAttribute()] 
    public static string HelloWorld() 
    { 
        return "<b>Hello World</b><br/>"; 
    } 
}

One thing to keep in mind when you declare a method in an aspx which needs to be accessed by the ModalPopupExtender control or any ASP.NET AJAX control is to apply the following attribute.
[System.Web.Services.WebMethod(), System.Web.Script.Services.ScriptMethodAttribute()]

In addition to the above method attributes one need to declare the method as a static method. If the method is not declared static then you may not be able to ping from the client side. In the case of web service the method need not be static. Some of the errors which you may face because of not declaring the method static or because of not applying the above attributes are listed below.

1. Web Service call failed: 12030
2. Web Service call failed: 500

If the above two errors popup you know what to do? First check whether the method attributes are applied and secondly see to it that the method is declared as static in the code behind.

Below is the mark up needed to display the content from a method in an aspx page.

<!--Web service content display demo-->
<asp:Panel ID="webServicePanel" runat="server" Width="300px" Height="300" BackColor="Azure"> 
    <asp:Label ID="outputContentLbl" runat="server" Text="Label"></asp:Label> 
    <asp:Button ID="clsBtn" runat="server" Text="Button" /> 
</asp:Panel> 
<asp:Button ID="webServiceCall" runat="server" Text="Click to see the output of a webservice in a popup." /> 
<cc1:ModalPopupExtender ID="ModalPopupExtender1"       runat="server"  DynamicServicePath="ModalPopup.aspx" 
    TargetControlID="webServiceCall"          OkControlID="clsBtn"          DynamicServiceMethod="HelloWorld"          DynamicControlID="outputContentLbl"          BackgroundCssClass="backgroundColor"          PopupControlID="webServicePanel" DropShadow="true">        
</cc1:ModalPopupExtender>

You can see in the above mark up everything is same except for the webservice related properties, highlighted in Maroon. DynamicServicePath is used to specify the url of the page. If left blank it will refer the same page. DynamicServiceMethod is the method name in the aspx/codebehind which will be pinged by the ModalPopupExtender to retrieve data. DynamicControlID is the ID of the control in which you would like to display the output of the method. DynamicControlID should have the ID of a control inside the ASP.NET Panel control in our case or any control inside whatever container control the user is making use for popup. Also if you have any argument then you can use DynamicContextKey to pass the string argument.
Hiding and Showing the ModalPopupExtender control using javascript
The above e.g. are quite straight forward and easy to implement. Unfortunately a developer’ life is not a bed of roses. There may arise a requirement where one has to call/show/hide the popup control using javascript. So lets see how to do exactly this. Below is the HTML markup.

<asp:Button ID="popupScriptBtn" runat="server" Text="Click to view the modal popup using javascript" OnClientClick=”javascript:showModalPopup();return false;” />
<asp:Button ID="popupBtn" runat="server" Text="Click to see the modal popup." /> 
<div ID="div1" runat="server" > 
    <asp:Panel ID="Panel1" runat="server" Style="display: none; padding:10px; border:1px; border-style:solid;" BackColor="#FF9933" Width="400px"> 
        <table id="Table1" style="background-color: #C0C0C0; width: 400px; height: 5px;"><tr><td><h3 style="text-align: center;" id="header">Modal Popup</h3></td></tr></table> 
        <p>This is a Modal Popup extender control. You are seeing this because you have clicked the hyperlink button.</p> 
        <p style="text-align: center;"><asp:Button ID="closeBtn" runat="server" Text="Close" /></p>        
    </asp:Panel> 
</div> 
<cc1:ModalPopupExtender ID="ModalPopupExtender" runat="server" TargetControlID="popupBtn" 
    PopupControlID="Panel1" OkControlID="closeBtn" 
    BackgroundCssClass="backgroundColor" 
    DropShadow="true" PopupDragHandleControlID="header" 
    CancelControlID="" Drag="true" RepositionMode="None" />

Above markup is pretty much same as the one we used at the beginning of the blog. The only difference being we have an extra ASP.NET button, clicking which we will show the ModalPopupExtender control with the help of javascript. In the above markup we have used the “OnClientClick” property to assign the javascript, showModalPopup, which needs to be called when the button is clicked. The javascript to show and hide the popup is pasted below.

<script type="text/javascript" language="javascript">
//Javascript function to hide the popup control. 
function closeModalPopup() 
{ 
    //Using the $find javascript method to retrieve the modal popup control. 
    var modalPopup = $find('<%=ModalPopupExtender.ClientID %>'); 
    if (modalPopup != null) 
    { 
        modalPopup.hide(); 
    } 
} 
//Javascript function to show the ModalPopupExtender control. 
function showModalPopup() 
{ 
    //Using the $find javascript method to retrieve the modal popup control. 
    var modalPopup = $find('<%=ModalPopupExtender.ClientID %>'); 
    if (modalPopup != null) 
    { 
        modalPopup.show(); 
    }    
} 
</script>

In the above javascript we have two functions. One to show the ModalPopupExtender control and another to hide the control. In both the function we are using $find shortcut method to retrieve the popup control. To know more about $find method please see this link. Once we have retrieved the modal popup control we are calling the show and hide methods of the control to show and hide the control respectively.
Using the modal popup control within a GridView control

There is nothing different here. In a grid if you want to link the ModalPopupExtender to a control inside the GridView you need to just convert the column into a template column and add the ModalPopupExtender control to the column and configure the necessary properties as discussed. Below is a sample code where I have added the ModalPopupExtender control in the header section as well in a column of GridView control.



<asp:GridView ID="backIssueGrid" runat="server" AutoGenerateColumns="False" 
            DataMember="issue" DataSourceID="backIssuesXML"> 
        <RowStyle BorderColor="Tan" BorderStyle="Solid" BorderWidth="1px" /> 
        <Columns> 
            <asp:TemplateField HeaderText="Back Issues" HeaderStyle-CssClass="headerText"> 
                <ItemTemplate> 
                    <asp:HyperLink ID="title" runat="server" 
                        Text='<%# XPath("@title") %>' CssClass="gridText" NavigateUrl='<%# XPath("url") %>'></asp:HyperLink> 
                    <asp:Panel ID="webServicePanel" runat="server" Width="300px" Height="300" BackColor="Azure"> 
                        <asp:Label ID="outputContentLbl" runat="server" Text="Label"></asp:Label> 
                        <asp:Button ID="clsBtn" runat="server" Text="Button" /> 
                    </asp:Panel> 
                    <cc1:ModalPopupExtender ID="ModalPopupExtender1" runat="server" DynamicServicePath="ModalPopup.aspx" 
                        TargetControlID="title" OkControlID="clsBtn" 
                        DynamicServiceMethod="HelloWorld" 
                        DynamicControlID="outputContentLbl"  
                        BackgroundCssClass="backgroundColor" PopupControlID="webServicePanel" 
                        DropShadow="true">        
                    </cc1:ModalPopupExtender> 
                </ItemTemplate> 
                <HeaderStyle CssClass="headerText"></HeaderStyle> 
                <ItemStyle BorderColor="Tan" BorderStyle="Solid" BorderWidth="1px" />                
            </asp:TemplateField> 
            <asp:TemplateField HeaderStyle-CssClass="headerText">                
                <ItemTemplate> 
                    <asp:TextBox ID="quantityTxt" Width="30" runat="server" Text='<%#XPath("@noOfCopies") %>' CssClass="gridText"></asp:TextBox> 
                </ItemTemplate> 
                <ItemStyle BorderColor="Tan" HorizontalAlign="Center" BorderStyle="Solid" BorderWidth="1px" /> 
                <HeaderStyle CssClass="headerText"></HeaderStyle> 
                <HeaderTemplate> 
                    <asp:ImageButton ID="ImageButton1" runat="server" ImageUrl="some.gif" />                    
                    <asp:Panel ID="webServicePanel2" runat="server" Width="300px" Height="300" BackColor="Azure"> 
                        <asp:Label ID="outputContentLbl1" runat="server" Text="Label"></asp:Label> 
                        <asp:Button ID="clsBtn" runat="server" Text="Button" /> 
                    </asp:Panel> 
                    <cc1:ModalPopupExtender ID="ModalPopupExtender2" runat="server" DynamicServicePath="ModalPopup.aspx" 
                        TargetControlID="ImageButton1" OkControlID="clsBtn" 
                        DynamicServiceMethod="HelloWorld" 
                        DynamicControlID="outputContentLbl1"  
                        BackgroundCssClass="backgroundColor" PopupControlID="webServicePanel2" 
                        DropShadow="true">        
                    </cc1:ModalPopupExtender> 
                </HeaderTemplate> 
            </asp:TemplateField> 
            <asp:TemplateField> 
                <ItemTemplate> 
                    <asp:Label ID="Label4" CssClass="gridText" runat="server" Text='<%# Add(XPath("@noOfCopies"), XPath("@price"))%>'></asp:Label> 
                </ItemTemplate> 
            </asp:TemplateField> 
            <asp:CommandField ShowSelectButton="True" ButtonType="Button" 
                SelectText="Remove" ControlStyle-CssClass="buttonText" > 
            <ControlStyle CssClass="buttonText"></ControlStyle> 
            <ItemStyle BorderColor="Tan" BorderStyle="Solid" BorderWidth="1px" /> 
            </asp:CommandField> 
        </Columns> 
        <EditRowStyle BorderStyle="Solid" /> 
    </asp:GridView>

In the above e.g. you can see the markups highlighted in green. In the first portion I have place a popup control in the “ItemTemplate” and hooked the ModalPopupExtender control to a hyperlink control. Pretty simple, isn’t it? In the second section I have put the popup control in the HeaderTemplate of the column and hooked it to a ImageButton. So when one clicks on the image button in the header he will see a popup. If you want you can add javascript “onmouseover” and “onmouseout” behavior to the image in the code behind by adding attributes to the ImageButton control.

In my case I had to show help text whenever the user clicks the header text so instead of adding ModalPopupExtender control to each and every HeaderTemplate what I did is added the ModalPopupExtender control somewhere in the aspx page and hooked it to a hidden control and on click of the header, used javascript to display the popup control. The reason why I took this approach is that if I put the ModalPoupExtender in each column’ header template, it will generate as many popup extenders as the number of columns. My popup control needs to display help text and these help text were retrieved from a method in the code behind/webservice. So I used a javascript function and passed parameters necessary to retrieve the help text. Also people who have similar kind of requirement where for e.g. you have a column and you need to show some help text or some detailed information based on some parameters you can also follow the same approach. The approach will reduce the amount of html being generated. With this approach I wanted to highlight the subtle feature of ModalPopupExtender control where one can hook up the control to a hidden control and use javascript to show the control. This method can be very useful for controls to which ModalPopupExtender cannot be attached. I think thats enough, lets see the code in action.

<asp:GridView ID="backIssueGrid" runat="server"
AutoGenerateColumns="False" DataMember="issue" 
DataSourceID="backIssuesXML"> 
        <RowStyle BorderColor="Tan" 
BorderStyle="Solid" BorderWidth="1px" /> 
        <Columns> 
            <asp:TemplateField 
HeaderStyle-CssClass="headerText"> 
                <HeaderTemplate> 
                    <asp:HyperLink ID="title" 
runat="server" Text="Name" CssClass="gridText" 
NavigateUrl='javascript:showModalPopup("helpOne" 
);'></asp:HyperLink> 
                </HeaderTemplate> 
                <ItemTemplate> 
                    <asp:HyperLink ID="title" 
runat="server" Text='<%# XPath("@title") %>' 
CssClass="gridText" NavigateUrl='<%# 
XPath("url") %>'></asp:HyperLink>                        </ItemTemplate> 
                <HeaderStyle 
CssClass="headerText"></HeaderStyle> 
                <ItemStyle BorderColor="Tan" 
BorderStyle="Solid" BorderWidth="1px" />                        </asp:TemplateField> 
            <asp:TemplateField 
HeaderStyle-CssClass="headerText">                       <ItemTemplate> 
                    <asp:TextBox 
ID="quantityTxt" Width="30" runat="server" 
Text='<%#XPath("@noOfCopies") %>' 
CssClass="gridText"></asp:TextBox> 
                </ItemTemplate> 
                <ItemStyle BorderColor="Tan" 
HorizontalAlign="Center" BorderStyle="Solid" 
BorderWidth="1px" /> 
               <HeaderStyle 
CssClass="headerText"></HeaderStyle> 
                <HeaderTemplate> 
                    <asp:HyperLink ID="title" 
runat="server" Text="Address" CssClass="gridText"                         NavigateUrl='javascript:showModalPopup("helpTwo" 
);'></asp:HyperLink>                                             </HeaderTemplate> 
            </asp:TemplateField>            
            <asp:CommandField 
ShowSelectButton="True" ButtonType="Button" 
SelectText="Remove" ControlStyle-CssClass="buttonText" > 
            <ControlStyle 
CssClass="buttonText"></ControlStyle> 
            <ItemStyle BorderColor="Tan" 
BorderStyle="Solid" BorderWidth="1px" /> 
            </asp:CommandField> 
        </Columns>        
</asp:GridView> 
<asp:XmlDataSource ID="backIssuesXML" 
runat="server" 
DataFile="~/Data/BackIssue.xml"></asp:XmlDataSou 
rce> 
<asp:HyperLink ID="title" runat="server" 
Style="display:none;"> </asp:HyperLink> 
        <asp:Panel ID="webServicePanel" 
runat="server" Width="300px" Height="300" 
BackColor="Azure"> 
            <asp:Label ID="outputContentLbl" 
runat="server" Text="Label"></asp:Label> 
            <asp:Button ID="clsBtn" 
runat="server" Text="Button" /> 
        </asp:Panel> 
<cc1:ModalPopupExtender ID="ModalPopupExtender1" 
runat="server" DynamicServicePath="ModalPopup.aspx" 
TargetControlID="title" OkControlID="clsBtn" 
DynamicServiceMethod="HelloWorld" 
DynamicControlID="outputContentLbl"  
BackgroundCssClass="backgroundColor" PopupControlID="webServicePanel" DropShadow="true">        
</cc1:ModalPopupExtender>

The above code has ASP.NET hyper link controls in the header template which calls a javascript function using its NavigateUrl property and passes a string value to the javascript function based on which the help text is retrieved. Also as you can see we have a ModalPopupExtender control outside of GridView. A javascript function is used to show the popup control when you click the hyper link controls inside the header template of the gridview. Also note the hyper link control outside the GridView which has its style set to “None” so that the control becomes invisible. The javascript which is executed on clicking the hyper link controls inside the GridView is pasted below.

//Javascript function to show the ModalPopupExtender control.
function showModalPopup(helpId) 
{ 
    var modalPopup = $find('<%=ModalPopupExtender1.ClientID %>'); 
    if (modalPopup != null) 
    { 
        modalPopup._DynamicContextKey = helpId; 
        modalPopup.show(); 
    }    
}

In the above javascript we are setting the “_DynamicContextKey” with the help of the method argument. The argument is passed by the hyper link controls in the header template of the GridView. DynamicContextKey are nothing but the string arguments to be passed to webservice/webpage method. So by varying the DynamicContextKey we can get different messages to be displayed in the ModalPopupExtender control.

The code behind method which is called by the ModalPopupExtender control is pasted below.

[System.Web.Services.WebMethod(), System.Web.Script.Services.ScriptMethodAttribute()]
    public static string HelloWorld(string contextKey) 
    { 
        return "<b>Hello World</b><br/>" + contextKey; 
    }

So that’ about working with ModalPopupExtender control. Below are some of the important javascript properties and methods of ModalPopupExtender control.

Method/PropertiesDescription
_DynamicControlID

Using this property you can set/retrieve the ID for the dynamic control i.e. the control which will show the output of the method being pinged by the modal popup extender control.

_DynamicContextKeyProperty to set/retrieve the string parameter for the function which will be called by the ModalPopupExtender control.
_DynamicServicePath

Property to set/retrieve the path for the webservice/webpage.

_DynamicServiceMethod

Property to set/retrieve the method which needs to be invoked or pinged to retrieve the output.

_PopupControlID

The property can be used to set/retrieve the ID of the control which will be shown as the popup. Normally it will be the ID of the ASP.NET panel control.

_PopupDragHandleControlID

The ID of the control clicking on which the popup control can be dragged.

_BackgroundCssClass

CSS class name for the background of the popup can be set/retrieved using this javascript property.

_DropShadow

Boolean value which can be set/retrieved to enable drop shadow. A value of “true” means drop shadow is enabled, false means it is disabled.

_Drag

Property to set/retrieve the drag facility. If you want to enable set it as true.

_OkControlID

This property can be used to set/retrieve the “Ok” button.

_CancelControlID

Property to set/retrieve the “Cancel” button id.

_OnOkScript

Property to set/retrieve the script which needs to fired when “Ok” button inside the popup is clicked.

_OnCancelScript

Property to set/retrieve the script which needs to fired when “Cancel” button inside the popup is clicked.

_xCoordinate

Property to set/retrieve the X coordinates of the popup control.

_yCoordinate

Property to set/retrieve the Y coordinates of the popup control.

_repositionMode

Property to set/retrieve the Reposition mode. Reposition mode has been discussed somewhere else in this document. The property accepts integer as its value. The various values and their corresponding reposition mode are as follows. 0 means “None”, 1 means “RepositionOnWindowResize”, 2 means “RepositionOnWindowScroll” and finally 3 means
“RepositionOnWindowResizeAndScroll”. Each of this mode is discussed above.

_id

One can set/retrieve the ID of the ModalPopupExtender control.

So that’ about our disussion on ModalPopupExtender control.


Try to know more,

Sandeep