Sunteți pe pagina 1din 11

Cross page postbacks in ASP.

NET

Back in the days of ASP.NET 1.x there was no easy way to make post-backs to pages different than the current page (so
called Cross Page Postbacks).
Asp.Net 2.0 fixed this with built-in features that allowed us to easily send information from one page to another.
Button control has property PostBackUrl that can be set to URL of any page in our ASP.Net WebSite where we want to
transfer all form values to.
Along with that Asp.Net 2.0 Page class has a property PreviousPage that allows us to get reference to the Page object
that initiated the postback (in other words to get the actual reference to the Page object of the aspx page on which user
clicked the Submit button on a HTML form).

So for example lets create two sample pages in our Web Application:
• SourcePage.aspx
• DestinationPage.aspx
In SoucePage in Html form we will put two TextBox controls (one for First Name and one for Last Name) and one Button
component and set its PostBackUrl property to "~/DestinationPage.aspx".
SourcePage.aspx:
<form id="form1" runat="server">
<div>
First Name:&nbsp;<asp:TextBox ID="FirstName" runat="server"></asp:TextBox><br />
Last Name:&nbsp;<asp:TextBox ID="LastName" runat="server"></asp:TextBox><br /><br />
<asp:Button ID="Button1" runat="server" Text="Submit To Destination Page"
PostBackUrl="~/CrossPagePostbacks/DestinationPage.aspx" />
</div>
</form>
When our user clicks the Submit button, all the values from the HTML Form on SourcePage.aspx will be transfered to
the DestinationPage.aspx and we will also be able to get reference to the SourcePage.aspx in our DestinationPage with
the PreviousPage property like this:
So in our DestinationPage.aspx.cs code-behind we can easily access two TextBox controls on SourcePage.aspx and
show them in two label controls like this:
protected void Page_Load(object sender, EventArgs e)
{ // first check if we had a cross page postback
if ( (PreviousPage != null) && (PreviousPage.IsCrossPagePostBack) )
{
Page previousPage = PreviousPage;
TextBox firstName = (TextBox)previousPage.FindControl("FirstName");
TextBox lastName = (TextBox)previousPage.FindControl("LastName");
// we can now use the values from TextBoxes and display them in two Label controls..
labelFirstName.Text = firstName.Text;
labelLastName.Text = lastName.Text;
}
}
You probably noticed that we first checked if PreviousPage property of current page (DestinationPage.aspx) is NOT
NULL, this is done to avoid running our code in case that user opens our DestinationPage.aspx directly, without running
a cross page postback.
Also here we checked the another PreviousPage property called IsCrossPagePostBack to see if we really had a
CrossPagePostback.
(If Server.Transfer is used to redirect to this page, IsCrossPagePostBack property will be set to FALSE.
TIP: We can be completely sure that we have a real CrossPagePostback ONLY IF:
1. Page.PreviousPage is NOT NULL,
2. PreviousPage.IsCrossPagePostback is true
This important to check to avoid errors in code.
Now this is very useful and i'm sure you are eager to use this in your next project. But wait, we are not over yet!
Finding the controls on PreviousPage with FindControl method and type-casting them from object to their real type is a
little messy.
It feels like there must be a better solution for this!
And here it is: We can use the <%@ PreviousPageType %> directive in the header of our DestinationPage.aspx like
this
<%@ PreviousPageType VirtualPath="~/SourcePage.aspx" %>
to declare our previous page type, and then we can access Public properties of the PreviousPage without typecasting.
Now all we need to do is to create some public properties on our SourcePage.aspx.cs to expose data/Controls we want
to the destionation page:
public partial class SourcePage : System.Web.UI.Page
{
public string FormFirstName
{
get { return FirstName.Text; }
}

public string FormLastName


{
get { return LastName.Text; }
}
}
And then we can change the Page_Load code in our DestinationPage.aspx to much cleaner code like this:
protected void Page_Load(object sender, EventArgs e)
{
// first check if we had a cross page postback
if ( (PreviousPage != null) && (PreviousPage.IsCrossPagePostBack) )
{
SourcePage prevPage = PreviousPage;
// we can now use the values from textboxes and display them in two Label controls..
labelFirstName.Text = prevPage.FormFirstName;
labelLastName.Text = prevPage.FormLastName;
}
}
SourcePage type used in the code is offcourse name of the partial class defined is SourcePage.aspx.cs that inherits
System.Web.UI.Page that is automatically created for us when we created new WebForm in VisualStudio.
When you set Forms Button PostbackUrl property to a page other than the current page, ASP.NET runtime adds new
JavaScript onclick event handler with a call to JavaScript function called WebForm_DoPostBackWithOptions, instead
of the usual __doPostback, that posts contents of current form to the specified target ASPX page.
Also a hidden field is generated on the source page HTML code called __PREVIOUSPAGE that contains info about the
source page that is used on the target page to build a reference to the originating page (the PreviousPage property).

How to write your own partial postback in ASP.NET


AJAX has been around for a while now, and an important feature of the AJAX implementation in the .NET
space is the partial post back functionality of web pages. This functionality has made the online experience
richer and smoother while decreasing bandwidth usage between the server and browser. How this
technology works is equally fascinating, and I am making an attempt to demonstrate how it works by taking
a look below the hood.
Background
At the heart of the partial post back construction is the XMLHttpRequest, a DOM API. It can be used inside a
web browser scripting language, such as JavaScript, to send an HTTP request directly to a web server
without having to reload the entire page and handling the response from the server again within the
scripting language. This data, in the form of XML, can then be used to manipulate the page elements on the
client side. On the server side, we implement an HttpHandler to handle the request and pass back data in a
valid XML form.
By doing so, we are preventing page refreshes and roundtrips of static data and content in the web pages.
Essential building blocks
1. XMLHttpRequest API
2. HTTPHandler
How the code works
When the button on the ASPX page has been clicked, a client side HTTP request is made using the
XMLHttpRequest API. This request is handled by an HttpHandler on the web server. The HttpHandler
receives the request, processes it, and sends back the response to the XMLHttp object on the ASPX page.
The XMLHttp object in turn consumes the response and renders the appropriate UI changes without the
browser having to do a full refresh of the page.
Using the code
XMLHttpRequest API
This API makes the client side request to the handler without the need for a full postback by the ASPX page.
The XML data is received by the XMLHttp object and used to populate a div element.
var xmlhttp;
function loadXMLDoc()
{ xmlhttp=null;
if (window.XMLHttpRequest)
{// code for all new browsers
xmlhttp=new XMLHttpRequest();
}
else if (window.ActiveXObject)
{// code for IE5 and IE6
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
if (xmlhttp!=null)
{
xmlhttp.onreadystatechange=state_Change;
xmlhttp.open("GET","http://localhost:45000/.tpl",true);
xmlhttp.send(null);
}
else
{
alert("Your browser does not support XMLHTTP.");
}
}

function state_Change()
{
if (xmlhttp.readyState==4)
{
if (xmlhttp.status==200)
{ document.getElementById('D').innerHTML=xmlhttp.responseText; }
else
{ alert("Problem retrieving XML data:" + xmlhttp.statusText); }
}
}

Httphandler
The HttpHandler code builds and sends a simple XML object called note, with a single element called
body. You can modify and implement your own logic here to do more complex stuff.
/// <summary>
/// Summary description for $codebehindclassname$
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{ context.Response.ContentType = "text/plain";
context.Response.Write("<note>");
context.Response.Write("<body>Partial postbacks" + " are awesome!</body>");
context.Response.Write("</note>");
}
public bool IsReusable
{
get { return false; }
}
}

How to update controls which are outside of updatepanel during partial


page rendering?

we generally used update panel to do the partial page postback, which means to
postback the controls which are only inside the update panel. For achieve this we
simply call Update() method for the corresponding Update Panel. This thing is quite
simple when we are trying to update any control which is inside the updatepanel
itself. But, The problem may come when we want to update the controls which are
outside of UpdatePanel and we need to update the same while updating then control
inside updatepanel.

To make it simple. Let’s consider below scenarios. In our web page, we have Two
labels (Label1 and Label2). Lable1 present inside the updatePanle and Label2 is in
the outside of updatePanel. We have one Button say Button1, which is also inside
the UpdatePanel. Now, our requirement is to update the Label2 while we are updating
Label1 by Clicking Button1.

below is the code block for above scenarios

view sourceprint?
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode=Conditional>
<ContentTemplate>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<asp:Button ID="Button1" runat="server" Text="Update Button"
onclick="Button1_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:Label ID="Label2" runat="server" Text="Label"></asp:Label>

Now, if we click on “Button1″, it will update only the content of Label1 not
Lable2.

The solutions is to use ScriptManager.RegisterDataItem() . Using RegisterDataItem()


methods we can register any control with the Particular Page ScriptManager
Instance. While registering we need to provide the Control name along with the data
item for the control which we want to render.
Below code block showing how to register the control which is outside of
UpdatePanel with the ScriptManager.

view sourceprint?
protected void Button1_Click(object sender, EventArgs e)
{ //Updating Label1 Text with the current Time Ticks
Label1.Text = DateTime.Now.Ticks.ToString();
//Register Label2 control with current DataTime as DataItem
ScriptManager1.RegisterDataItem(Label2, DateTime.Now.ToString());
}
If we click on Button1 now, it will update the text of Label1, but though we have
registered the Label2 with the script manager still its value will not be reflect.
As We have just registered the control.
The next step is to update the control value. For that we need to take help of
PageRequestManager and add_pageLoaded method. The pageLoaded event is raised after
all content on the page is refreshed, either because of a full-page postback or an
partial postback. You can read the details of same from MSDN.
We need to write below code in client side which will update the content values.
view sourceprint?
var pageInstance = Sys.WebForms.PageRequestManager.getInstance();
pageInstance.add_pageLoaded(UpdateLabelHandler);
function UpdateLabelHandler(sender, args)
{
var ControldataItems = args.get_dataItems();
if ($get('Label2') !== null)
$get('Label2').innerHTML = ControldataItems ['Label2'];
}
Let me explain the codeblock, Sys.WebForms.PageRequestManager.getInstance(), will
return the current Instance of PageRequestManager Class. From that Instance we can
invoke the add_PageLoaded method. We have added UpdateLabelHandler() which take
“args” as an Argument. This args conatins the data items for the registred
controls. we can call args.get_dataItems()to retreive the data from the dataitem
collections. After that we have set the Control Value by from the data item
collection using $get(‘Label2′).innerHTML = ControlsdataItems['Label2']; . So, In
case we have multiple control that we need to update we can use the control name to
retrieve the value form the ControldataItems.
Callback & Controls Rendering (Manually Partial Page Rendering)
1. Why Should I read this article
As Callback doesn’t cause postback and page rendering neither full nor even partial. We can communicate
with server (IIS) and our server side code runs there successfully and could rebind our controls like
Dropdownlist, Gridview, Listview, Datalist, Repeater or any server side control to which you assign data but
problem is when page wont render, its controls wont render and if controls wont render then changes wont
reflect and when changes wont reflect there wont be anything at front end to show on webpage.
Article is mainly about Callback and Rendering Controls but through this tutorial you can also learn many
other things like brief introduction of Postback, Rendering, Create server side controls dynamically, Create
Datatable dynamically in memory to bind with create server side controls means binding, get server side
control at client side and set their properties and registering client side event of server side control
from/through server side code. First of all, I would like to brief some terms which I believe every web
developer should aware of.
2. Postback
Postback is a mechanism of communication between client-side (browser) and server-side (IIS). Through
postback all contents of page/form(s) sent to the server from client for processing and after following page
life cycle all server side contents get render into client side code and client (browser) display that contents.
Callback is another way of communication between server and client. Callback doesn�t follow the page life
cycle which followed by in standard postback and doesn�t even cause Rendering.
3. Rendering
Rendering is process of converting server side code/contents into client side code/content so client
(browser) can understand that code and could display the output. Browser can understand or you may say
decode code of client side languages and scripts like HTML, DHTML, XHTML, Javascript, Vbscript and a long
list. If rendering wont happen then changes won�t reflect which happens on server at client side. Ajax
leverages partial postback automatically whereas callback doesn�t cause, so programmer needs to perform
that task manually. ASP.NET team has created RenderControl method with its each control so by using that
control we can render our control very easily.
If you have read my previous article you may skip following section from 4 and 5.
4. CALLBACK
CALLBACK is lightweight process, It uses well known xmlhttp object internally to call server side method, it
doesn�t cause page postback so doesn�t cause page rendering so we to show output at client side we
need to make output html ourselves and render controls manually.
5. ICALLBACKEVENTHANDLER
ICALLBACK implemented in asp.net by using ICALLBACKEVENTHANDLER interface has two methods, one of
them used to be call from javascript (client side code) and other one return result asynchronously back to
javascript function.
We just need to perform some action through server side code at server side and needs to return results
but results could are in instance or object of any class which could be not easy for javascript code to handle
easily so here we prefer JSON which stands for Javascript Object Notation.
7. Real Time Scenario with implementation
Suppose we have categories, subcategories, products data and needs to populate categories and
subcategories which depend upon categories data would be populate in two different dropdownlists. For
products data which is multicolumn and we need to show that data in tabular format so I would prefer
Gridview control.
So the situation would be load/populate categories on Page_Load and load/populate subcategories on the
basis of selected category using callback and finally load products into Gridview on the basis of selected
subcategory.
Before starting coding, I would like to write Pseudo code for better understanding.
8. Pseudo Code
1. Create Server side controls e.g. Dropdownlists and Gridview
2. Load Categories on Page load
3. Implement ICallbackEventHandler interface
4. Create subcategories data in server memory to bind to Subcategory dropdownlist.
5. Render control (subcategory dropdownlist) and show output.
6. Create products data in server memory to bind to Products gridview.
7. Render Control (products gridview) and return rendered contents to client side to show
8. Set innerHTML of each control by rendered contents
CREATE CONTROLS (DROPDOWNLISTS, GRIDVIEW)
<b>Categories:</b> <br />
<asp:DropDownList ID="ddlCategories" runat="server" Width="100" onchange="CallSrv(this);">
</asp:DropDownList> <br />
<b>Subcategories</b>:
<div id="ddlSubcategories">
</div> <b>Products:</b>
<div id="grvProducts"> </div>
CALLBACK SERVER SIDE CODE
Let’s implement ICALLBACKEVENTHANDLER to call server side method asynchronously step by step J
Implement Server Side (C#) Page/Control class by System.Web.UI.ICallbackEventHandler
Following are definition of two methods which needs to implement:
RaiseCallbackEvent method invoke by javascript function
public void RaiseCallbackEvent(string eventArgument)
{
//split eventArgument parameter to get command name and then value to perform operation
//like if command is by Category then we need to load sub categories and if command is by subcateogry
//then we need to load products
string[] commands = eventArgument.Split(",".ToCharArray());
//check command
if (commands[0].Equals("LoadSubCategory"))
{
//create sub category control dynamically
DropDownList ddlSubcategories = new DropDownList();
switch (commands[1])
{
//populate sub category data on the basis of category
case "Autos":
ddlSubcategories.Items.Add("Cars");
ddlSubcategories.Items.Add("Bikes");
break;
case "Electronics":
ddlSubcategories.Items.Add("Computers");
ddlSubcategories.Items.Add("TV");
break;
}
//set client side event
ddlSubcategories.Attributes.Add("onchange", "CallSrv(this);");
//primarily rendered output would come in string builder (sb) object
//through stringwriter which would get data from htmltextwriter
//which would get data from RenderControl method
System.Text.StringBuilder sb = new System.Text.StringBuilder();
System.IO.StringWriter sw = new System.IO.StringWriter(sb);
HtmlTextWriter htw = new HtmlTextWriter(sw);
//render sub categories dropdownlist
ddlSubcategories.RenderControl(htw);
//set prefix command name so at client side we could know which control to load actually and
//set rendered string
this.RenderedOutput = "LoadSubCategory," + sb.ToString();
}
//check command
else if (commands[0].Equals("LoadProducts"))
{
//create data table in memory and populate that wid sample/example data to show on webpage
DataTable dtProducts = new DataTable();
//create columns of data table
dtProducts.Columns.Add("ProductName");
dtProducts.Columns.Add("ProductDescription");
dtProducts.Columns.Add("ProductPrice");
//declare row to fill up with data
DataRow drProduct;
switch (commands[1])
{
//create data in memory (datatable) to populate in gridview
case "Cars":
drProduct = dtProducts.NewRow();
drProduct["ProductName"] = "Honda";
drProduct["ProductDescription"] = "2000 CC";
drProduct["ProductPrice"] = "$1000";
dtProducts.Rows.Add(drProduct);
drProduct = dtProducts.NewRow();
drProduct["ProductName"] = "Toyota";
drProduct["ProductDescription"] = "1800 CC";
drProduct["ProductPrice"] = "$800";
dtProducts.Rows.Add(drProduct);
break;
case "Bikes":
drProduct = dtProducts.NewRow();
drProduct["ProductName"] = "Pak Hero";
drProduct["ProductDescription"] = "125 CC";
drProduct["ProductPrice"] = "$100";
dtProducts.Rows.Add(drProduct);
drProduct = dtProducts.NewRow();
drProduct["ProductName"] = "Honda";
drProduct["ProductDescription"] = "250 CC";
drProduct["ProductPrice"] = "$150";
dtProducts.Rows.Add(drProduct);
break;
case "Computers":
drProduct = dtProducts.NewRow();
drProduct["ProductName"] = "Dell";
drProduct["ProductDescription"] = "P4 Centrino";
drProduct["ProductPrice"] = "$400";
dtProducts.Rows.Add(drProduct);
drProduct = dtProducts.NewRow();
drProduct["ProductName"] = "IBM";
drProduct["ProductDescription"] = "P4 Think PAD";
drProduct["ProductPrice"] = "$350";
dtProducts.Rows.Add(drProduct);
break;
case "TV":
drProduct = dtProducts.NewRow();
drProduct["ProductName"] = "Sony";
drProduct["ProductDescription"] = "Plasma";
drProduct["ProductPrice"] = "$600";
dtProducts.Rows.Add(drProduct);
drProduct = dtProducts.NewRow();
drProduct["ProductName"] = "Philips";
drProduct["ProductDescription"] = "Projection";
drProduct["ProductPrice"] = "$550";
dtProducts.Rows.Add(drProduct);
break;
}
//create gridview to bind with created datable to show output
GridView grvProducts = new GridView();
grvProducts.DataSource = dtProducts;
grvProducts.DataBind();
//primarily rendered output would come in string builder (sb) object
//through stringwriter which would get data from htmltextwriter
//which would get data from RenderControl method
System.Text.StringBuilder sb = new System.Text.StringBuilder();
System.IO.StringWriter sw = new System.IO.StringWriter(sb);
HtmlTextWriter htw = new HtmlTextWriter(sw);
//render sub categories dropdownlist
grvProducts.RenderControl(htw);
//set prefix command name so at client side we could know which control to load actually and
//set rendered string
this.RenderedOutput = "LoadProducts," + sb.ToString();
}
}
/// <summary>
/// Execute/Fires when RaiseCallbackEvent code runs completely
/// </summary>
/// <returns></returns>
public string GetCallbackResult()
{
//return rendered string with command name
return RenderedOutput;
}
In Page_Load or Page_Init event
Following statements are used to register client side methods.
CallServer(arg, context) as name implies would use to call/raise server side method which was
RaiseCallbackEvent string eventArgument)
ReceiveServerData(arg, context) would use to get result through arg parameter by GetCallbackResult()
//Register Client Script for Callback and populate categories
protected void Page_Load(object sender, EventArgs e)
{
ClientScriptManager scriptMgr = Page.ClientScript;
String cbReference = scriptMgr.GetCallbackEventReference(this, "arg", "ReceiveServerData", "");
String callbackScript = "function CallServer(arg, context) {" + cbReference + "; }";
cm.RegisterClientScriptBlock(this.GetType(),"CallServer", callbackScript, true);
if (!Page.IsPostBack)
{
//Load Products Data
this.ddlCategories.Items.Add("Select");
this.ddlCategories.Items.Add("Autos");
this.ddlCategories.Items.Add("Electronics");
}
}
CALLBACK CLIENT SIDE CODE
<script language="javascript" type="text/javascript">
//Runs when GetCallbackResult() executes and return result through arg param
function ReceiveServerData(arg, context)
{
//split command and contents (rendered data)
var cmd_content = arg.split(',');
//check command
if (cmd_content[0] == 'LoadSubCategory')
{
//set rendered contents to sub category div to show subcategories according to categories
document.getElementById('ddlSubcategories').innerHTML = cmd_content[1];
}
else
{
//set rendered contents to products div to show products according to categories and sub categories
document.getElementById('grvProducts').innerHTML = cmd_content[1];
}
}
//invoke by categories/subcategories dropdownlist to communicate with server for processing
function CallSrv(ddl)
{
//check command and determine either this method invoked by
//Categories Dropdownlist or by Subcategories Dropdownlist
if (ddl.id == 'ddlCategories')
{
if(ddl.value != 'Select')
{
//Set command and value to load data accordingly and call server side method RaiseCallbackEvent
CallServer('LoadSubCategory' + ',' + ddl.value, '');
}
}
else
{
//Set command and value to load data accordingly and call server side method RaiseCallbackEvent
CallServer('LoadProducts' + ',' + ddl.value, '');
}
}
</script>
Thants it. These are the steps which you need to use to call and get result from server side code using
ICALLBACK.
Asynchronously output would be within a millisecond and without Postback J
const, static and readonly

const vs. readonly


const and readonly perform a similar function on data members, but they have a few important
differences.

const
A constant member is defined at compile time and cannot be changed at runtime. Constants are declared as
a field, using the const keyword and must be initialized as they are declared. For example;
public class MyClass
{
public const double PI = 3.14159;
}

PI cannot be changed in the application anywhere else in the code as this will cause a compiler error.
Constants must be a value type (sbyte, byte, short, ushort, int, uint, long, ulong, char,
float, double, decimal, or bool), an enumeration, a string literal, or a reference to null.
Since classes or structures are initialized at run time with the new keyword, and not at compile time, you
can't set a constant to a class or structure.
Constants can be marked as public, private, protected, internal, or protected internal.
Constants are accessed as if they were static fields, although they cannot use the static keyword.
To use a constant outside of the class that it is declared in, you must fully qualify it using the class name.
readonly
A read only member is like a constant in that it represents an unchanging value. The difference is that a
readonly member can be initialized at runtime, in a constructor as well being able to be initialized as they
are declared. For example:
public class MyClass
{
public readonly double PI = 3.14159;
}

or
public class MyClass
{
public readonly double PI;

public MyClass()
{
PI = 3.14159;
}
}

Because a readonly field can be initialized either at the declaration or in a constructor, readonly fields
can have different values depending on the constructor used. A readonly field can also be used for
runtime constants as in the following example:
public static readonly uint l1 = (uint)DateTime.Now.Ticks;

Notes
• readonly members are not implicitly static, and therefore the static
keyword can be applied to a readonly field explicitly if required.
• A readonly member can hold a complex object by using the new keyword at
initialization.

static
Use of the static modifier to declare a static member, means that the member is no longer tied to a
specific object. This means that the member can be accessed without creating an instance of the class. Only
one copy of static fields and events exists, and static methods and properties can only access
static fields and static events. For example:
public class Car
{
public static int NumberOfWheels = 4;
}

The static modifier can be used with classes, fields, methods, properties, operators, events and
constructors, but cannot be used with indexers, destructors, or types other than classes.
static members are initialized before the static member is accessed for the first time, and before the
static constructor, if any is called. To access a static class member, use the name of the class instead
of a variable name to specify the location of the member. For example:
int i = Car.NumberOfWheels;

S-ar putea să vă placă și