Skip navigation

Get a Rich UI With WinForms

Use a DataReader to enumerate multiple sets of query results.

Ask the PRO

LANGUAGES: C#

ASP.NET VERSIONS: 1.0 | 1.1

 

Get a Rich UI With WinForms

Use a DataReader to enumerate multiple sets of query results.

 

By Jeff Prosise

 

Q: I'm interested in using Windows Forms controls to build rich user interfaces in ASP.NET Web pages. I know how to deploy the controls and access their properties and methods from client-side script. Is it also possible to process a Windows Forms control's events in the browser?

 

A: It's no secret that one way to overcome the limitations of HTML and endow browser-based clients with rich user interfaces is to host Windows Forms controls in Web pages. As an example, here's a derived class named WebSlider that encapsulates a Windows Forms TrackBar control:

 

namespace Wintellect

{

    public class WebSlider :

        System.Windows.Forms.TrackBar {}

}

 

If this source-code file is compiled into a DLL named WebSlider.dll and deployed on a Web server, this tag declares an instance of it, causing a vertical TrackBar control to appear on the page:

 

  classid="http:WebSlider.dll#Wintellect.WebSlider"

  width="64" height="256">

  

  

  

  

  

 

The first time the page is accessed, Internet Explorer downloads the DLL and, with the .NET Framework's help, caches it on the client. The two chief requirements are that the client must be running Internet Explorer 5.01 or higher and must have the .NET Framework installed.

 

Accessing the control's properties and methods using client-side script is simplicity itself. If the form containing the control is named MyForm, this JavaScript statement moves the TrackBar thumb to position 5 by setting the control's Value property:

 

MyForm.Slider.Value = 5;

 

Writing client-side script that processes events fired by the control, however, is less straightforward. First, you must define an interface that encapsulates the events you wish to expose to the browser, and you must instruct the .NET Framework to expose the interface's members through a COM IDispatch interface. Then, you must associate this interface with the control.

 

Figure 1 contains the source code for a class derived by System.Windows.Forms.TrackBar that exposes the Scroll events fired in response to thumb movements to unmanaged code. The IWebSliderEvents interface defines the event as a method and assigns it a dispatch ID. (In COM, all methods exposed through an IDispatch interface require unique integer dispatch IDs.) Note that the method signature exactly matches that of the Scroll event defined in the base class. The [InterfaceType] attribute tells the .NET Framework to expose the IWebSliderEvents interface to unmanaged code as an IDispatch interface. The [ComSourceInterfaces] attribute adorning the class definition lets the framework know that WebSlider should support IWebSliderEvents as a source interface, which is COM speak for an interface used to source (fire) events.

 

using System;

using System.Runtime.InteropServices;

 

namespace Wintellect

{

   [ComSourceInterfaces (typeof (IWebSliderEvents))]

  public class WebSlider : System.Windows.Forms.TrackBar {}

 

   [InterfaceType (ComInterfaceType.InterfaceIsIDispatch)]

   public interface IWebSliderEvents

  {

     [DispId (1)] void Scroll (Object sender, EventArgs e);

  }

}

Figure 1. This Windows Forms TrackBar control derivative exposes Scroll events to unmanaged code.

 

Figure 2 lists an .aspx file you can use to test the WebSlider control. The tag declares a control instance. The for and event attributes in the

Figure 2. This .aspx file creates a WebSlider control and responds to Scroll events using client-side script.

 


Figure 3. Here's the WebSlider control in action. A client-side event handler continually updates the number shown below the control as the thumb moves.

 

Note that in order for unmanaged code hosted by a browser to "see" events fired from managed code, the assembly containing the control - in this case, WebSlider.dll - must be granted full trust on the client computer. (For security reasons, managed code can call unmanaged code only if it is granted permission to do so.) You can use the Microsoft .NET Framework wizards found in Control Panel\Administrative Tools to grant the assembly full trust. You must grant this permission for this example to work.

 

Q: Can you use a DataReader to enumerate the results of a query that produces multiple result sets?

 

A: You bet. The secret is the DataReader's NextResult method, which moves the virtual cursor maintained by the DataReader to the next result set. This code uses a compound query to create a SqlDataReader that encapsulates two result sets, then it outputs the first column in each result set to a console window:

 

SqlConnection connection = new SqlConnection

   ("server=localhost;database=pubs;uid=sa");

 

try {

  connection.Open ();

  SqlCommand command = new SqlCommand

     ("select title from titles; " +

     "select au_lname from authors", connection);

  SqlDataReader reader = command.ExecuteReader ();

 

  do {

    while (reader.Read ())

    Console.WriteLine (reader[0]);

    Console.WriteLine ();

  } while (reader.NextResult ());

}

finally {

  connection.Close ();

}

 

The ASPX file in Figure 4 demonstrates how you might use this knowledge in a Web page. Figure 4 uses the same compound query to initialize two DataGrids with one DataReader. Note the call to NextResult between calls to DataBind. This call points the cursor to the second result set prior to binding to the second DataGrid. This feature of the DataReader classes is especially handy when using stored procedures that return two or more result sets.

 

<%@ Import Namespace="System.Data.SqlClient" %>

 

  

    

      

      

      

    

  

 

Figure 4. This ASP.NET page uses a single SqlDataReader to initialize two DataGrids with two sets of query results.

 

Q: How do I assign a client-side OnClick handler to an ASP.NET button control? If I include an OnClick attribute in the control tag, ASP.NET looks for a server-side event handler with the specified name.

 

A: Because OnClick is a legal client- and server-side attribute, you must add OnClick attributes that reference client-side handlers programmatically to tags that declare runat="server" button controls. Suppose, for example, that the button is declared this way:

 

  RunAt="server" />

 

To configure button clicks to call a client-side event handler named confirmClick, include this statement in the page's Page_Load method:

 

SampleButton.Attributes.Add ("onclick",

    "confirmClick();");

 

The Attributes collection is a great way to add and manipulate programmatically the HTML attributes output by server controls.

 

Q: How does ASP.NET generate session IDs? Are they random? Predictable session IDs increase the risk of session hijacking.

 

A: ASP.NET uses nonsequential session IDs. Specifically, it uses the .NET Framework Class Library's System.Security.Cryptography.RNGCryptoServiceProvider class to generate highly random 120-bit session IDs. Sessions still can be hijacked by stealing session cookies or, if cookieless session state is being used, by reading session IDs from the browser's address bar. But ASP.NET's use of random session IDs should prevent the hijacking of sessions by guessing session IDs.

 

The sample code in this article is available for download.

 

Jeff Prosise is the author of several books, including Programming Microsoft .NET from Microsoft Press. He's also a co-founder of Wintellect (http://www.wintellect.com), a software-consulting and education firm that specializes in .NET. Have a question for this column? Submit queries to [email protected].

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish