Client Callbacks in ASP.NET 2.0

xiaoxiao2021-03-06  53

http://www.codeproject.com/aspnet/clientCallbackAspnet2.asp

Table of contents

Introduction

Compatibility Linked Drop Downs

Requirements Database Structure Code

Basics Client Callback Observations Complete Code

Please Read Fredrik Normén's Fabulous Introduction On Client-Call Back Before Reading this. This BRIEF TUTORIAL IS SIMPLY A More Realistic Example of Using The Technology Which HE EXPLAINS.

Introduction

. One of the new features in ASP.Net 2.0 is the ability to call server-side code from client-side code While this is not something new, a new simpler and cleaner mechanism is now available:. Client callback The general idea is to have some type of hook, client-side functions (JavaScript) can use to utilize powerful server-side functions. A key benefit to this closing the gap on desktop applications with respect to cleaner, richer and more responsive applications. Fredrik Normén has a Great blog entry explaining how it it works and how to use it. this brief Tutorial is Simply Written to showcase a more realistic example.

CompaTibility

Its important to note that Client Callback uses XmlHttp, which, as far as I know, only works in IE. Hopefully workarounds and third party solutions are not far away, which'll make this a truly powerful weapon to have in our arsenal.

Linked Drop Downs

The example I'll be doing will be a simple example of having values ​​in a dropdownlist linked to values ​​in another dropdownlist. A couple such examples would be a list of states / provinces for a selected country, or a list of departments in an organization . Our example will use the organization / departments example. Without using a method like client callback, we'd either have to dump large amounts of [hard to maintain] Javascript arrays and do a lot of client-side processing, or postback each time the value in the dropdownlist changed. Each solution, while workable, had some serious drawbacks. Using JavaScript could quickly become unwieldy, posting-back can cause even the best surfers to be confused for a couple seconds.Requirements

Our Requirements Are Simple:

Two dropdownlists are displayed to users The first dropdownlist contains all of the Canadian Governments Departments The 2nd dropdownlist contains all of the primary sections within the selected department A department may not have any sections We can not use postback, must only support IE, and have to keep The JavaScript to a minimum

No quberm!

Database structure

Keeping with our entire "Simple" Theme, Our Database Structure IS VERY SIMPLE:

The SQL Script To Create Our Table:

Create Table DBo.organization

OrganizationId Int Idnessity (1, 1) Not Null Constraint

[Pk_organization] Primary Key Clustered,

[Name] VARCHAR (255),

Parentid Int Null Constraint [fk_parent_organization]

Foreign Key References Organization (OrganizationID)

) On [primary]

Go

Basically, all our top-level departments will have a ParentId of NULL, while our sections will have a ParentId that is the same as their Departments OrganizationId. In your case you might have a many-many relationship, or your entities might not reside in The Same Table, IN That Case Simply Change The Data-Access Code We'll Be Using, But The Client Callback Code Stays The Client Callback Code Stays The Client Callback Code Stays The Client Callback Code Stays The Client Callback Code Stays The Client Callback Code Stays The Same. And to Make This A Complete Example, Some Sample Data: Insert INTO Organization

VALUES ('Agriculture and Agri-Food Canada ", NULL)

INSERT INTO ORGANIZATION

VALUES ('Bank of Canada', NULL)

INSERT INTO ORGANIZATION

Values ​​('Cadets Canada', NULL)

INSERT INTO ORGANIZATION

VALUES ('Canada Lands Company Limited', NULL)

INSERT INTO ORGANIZATION

VALUES ('Canadian Rural Partnership ", 1)

INSERT INTO ORGANIZATION

VALUES ('Co-Operatives Secretariat', 1)

INSERT INTO ORGANIZATION

VALUES ('Fish and Seafood On-line', 1)

INSERT INTO ORGANIZATION

VALUES ('Bank Notes', 2)

INSERT INTO ORGANIZATION

VALUES ('Currency Museum', 2)

INSERT INTO ORGANIZATION

VALUES ('Old Port of Montréal Corporation Inc.', 3)

INSERT INTO ORGANIZATION

VALUES ('Parc DownsView Park Inc.', 3)

Code

Basics

Our HTML WILL Consist of Two DropdownList WebControls:

1:

2:

For Now, Our Page_load Will Be Pretty Basic:

1: Private void Page_load (Object Source, Eventargs E) {

2: IF (! Page.ispostback) {

3: DataTable DT = GETORGANIZATIONS ();

4: DataView DV = DT.DEFAULTVIEW;

5: dv.rowfilter = "parentid is null"; 6: Parentorganizations.DataSource = DV;

7: Parentorganizations.DataTextField = "Name";

8: Parentorganizations.DataValuefield = "OrganizationID";

9: Parentorganizations.DATABIND ();

10: Parentorganizations.Items.Insert (0, New ListItem ("SELECT", "0"));

11:}

12:}

We get a datatable (We'll Look At the Getorganization () Function Next) [Line: 3], Get ITS Default View [line: 4] and filter it sowE Only Get Our Top-Level Departments [Line: 5]. Weim: 6-9] and add an option at the top for improved user-friendlines [line: 10] .the getorganizations () Function is your Typical Dal Method:

1: Private DataTable Getorganizations () {

2: DataTable DT = (DATATABLE) Cache ["Organizations"];

3: if (dt == null) {

4: SqlConnection Connection = New SqlConnection (Connectionstring);

5: SQLCommand command = new SQLCommand

"SELECT * from Organization Order By Name", Connection;

6: command.commandtype = commandtype.text;

7:

8: SqlDataAdapter Da = New SqlDataAdapter (Command);

9: DT = New DataTable ();

10: Try {

11: Connection.open ();

12: da.fill (dt);

13: Cache.Insert ("Organizations", DT, NULL,

DateTime.now.addhours (6), Timespan.zero;

FINALLY {

15: Connection.dispose ();

16: Command.dispose ();

17: da.dispose ();

18:}

19:}

20: Return DT;

twenty one: }

There's really nothing fancy here. Notice though that we get all Departments / Sections, that's why we have to filter for ParentId IS NULL in the Page_Load. If your entities were in two separate table, you could get your top level entities here, and simply Create a 2nd function for your child-enttive, Which We'll Be Using Shortly.Client Callback

Now we'll make all the changes necessary to make this magical callback work. Again, you really have to read Fredrik's blog before going on as I'm not going to go into any details.The first thing we do is add to our Page_Load In Order to Hookup and Register All Our Client Callback Code:

1: Private void Page_load (Object Source, Eventargs E) {

2: IF (! Page.ispostback) {

3: DataTable DT = GETORGANIZATIONS ();

4: DataView DV = DT.DEFAULTVIEW;

5: dv.rowfilter = "parentid is null";

6: Parentorganizations.DataSource = DV;

7: Parentorganizations.DataTextField = "Name";

8: Parentorganizations.DataValuefield = "OrganizationID";

9: Parentorganizations.DATABIND ();

10: Parentorganizations.Items.Insert (0, New ListItem ("SELECT", "0"));

11:

12: Parentorganizations.attributes.add ("onchange",

"GetChildren (this.Options [this.selectedIndIndex] .value, 'DDL');")

13: String Callback = page.getcallbackeventreference (this, "arg",

"ClientCallback", "Context", "ClientCallBackeRr");

14: String ClientFunction = "Function getChildren (arg, context) {"

Callback ";

15: page.clientscript.registerClientScriptBlock (this.gettype (),

"GetChildren", ClientFunction, TRUE;

16:}

17:}

On [line: 12] we add an onChange JavaScript event to our dropdownlist so that it calls the GetChildren () Javascript function This is the proxy-function to our server-side callback function Notice that the first JavaScript parameter will be the value.. of the selectedOption (in other words, the OrganizationId) .d Next we use the Page to create the JavaScript string that'll actually do the callback. [line: 13] We wrap the string in our proxy GetChildren Javascript function [line: 14 ]. Finally We Register The Script on The Page: 15] .next, makessa Your Page Implements iCallBackeventhandler:

1: Public Partial Class Index_aspx: IcallbackeventHandler {

2: ...

3:}

.

1: Public String RaiseCallBackeVent (String Eventargument) {

2: INT PARENTID

3: IF (int32.tryparse (eventargument, out parentid) {

4: DataTable DT = Getorganizations ();

5: DataView DV = DT.DEFAULTVIEW;

6: dv.rowfilter = "parentid =" parentid.toString ();

7: StringBuilder SB = New StringBuilder ();

8: for (int i = 0; i

9: sb.append (DV [i] ["OrganizationID"]);

10: sb.append ("^");

11: sb.append (DV [i] ["name"]);

12: sb.append ("|");

13:}

14: Return Sb.toString ();

15:}

16: Return "";

17:}

Again, there's really nothing fancy here All we are doing is using the organizationId which is passed as eventArgument to get all sections who have a matching ParentId. [Line: 6] We loop through the matching sections [line: 8]. And create a String in the format of id ^ name | id ^ name | ID ^ name [line: 9-12]. Finally We return out [line: 14]. if anything wrong or no records were found, an Empty String Will BE returned.The last step is to create our Javascript function that'll handle the return of our server-side function Back in our modified Page_Load, we said this function would be named ClientCallBack:. 1: