Technology and Community

Jim O'Neil

Subscribe to Jim O'Neil: eMailAlertsEmail Alerts
Get Jim O'Neil: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn

Related Topics: CEP on Ulitzer

PowerBuilder: Article

The Debut of DataWindow.Net

An overview of the architecture Part 1

Listing 1 provides code segments from a representative approach for managing a transaction in ADO.NET to update a DataStore. In an actual application these various code fragments would likely appear in different events or scripts. Also, for clarity each fragment assumes that the System.Data and Sybase.DataWindow namespaces have been explicitly declared within the respective modules via the directive.

The design pattern for implementing events in .NET is based on the use of delegates (or event handlers), which are specialized classes that provide a callback mechanism to methods or, more specifically, events that share the same signature as the delegate. One or more methods can be associated with a given event handler so that whenever the associated event is triggered, those methods on the receiving object will execute. The event itself is initiated when code elsewhere in an application invokes a method on the target object with the specific name "On" followed by the name of the desired event.

The DataWindow uses this same .NET paradigm to implement the events of the DataStore and DataWindow control, with the added twist that the destination and sometimes the source of the events are within the unmanaged code of the DataWindow server engine. For applications that use the core functionality of the DataStore and DataWindowControl classes - the DataWindowChild class has no events - the details of how the event processing is implemented are not a primary concern; however, if you plan to extend DataWindow functionality to include new custom events, you'll need to ensure that the design conforms to the .NET Framework delegate model.

When writing code for events, you'll immediately find that many of their names have been modified from their analogs in PowerBuilder to conform to .NET naming standards. A second difference you'll notice is that regardless of the event, you'll always have two specific arguments available:

  • sender: A System.Object reference indicating the class that originated the event
  • e: An object or descendant of System.EventArgs that contains additional information relevant to the event

    Optionally, a specialized descendant class System.CancelEventArgs can be used (or extended) whenever an event is cancelable. As an example, in RowFocusChanging, if it is determined that the current row should not be allowed to change, you can set the Cancel property of the argument class to true to prevent the RowFocusChanged event from firing. In PowerBuilder, you would have done this by returning the value of 1 from the RowFocusChanging event or would have used the deprecated SetActionCode method.

    For the DataStore class, most events have an argument structure that's specialized for the specific event type. For instance, the retrieve events (BeginRetrieve, RowRetrieved, and EndRetrieve) are passed row count and row number data via a RetrieveEventArgs class instance (or descendant thereof). Likewise, for the print events the page and copy numbers are provided in descendants of PrintEventArgs, and for the EndUpdate event the number of rows deleted is available in EndUpdateEventArgs.

    Of note to the DataStore class and to DataWindowControl by virtue of inheritance, a new DataWindowCreated event not currently available to PowerBuilder users is provided. The DataWindowCreated event fires whenever a new DataWindow object is assigned to the DataStore or DataWindow control, a type of "postopen" event for those familiar with that concept used in the PowerBuilder Foundation Classes (PFC). This construct is particularly important in form instantiation code where the nature of the .NET event processing coupled with internal DataWindow engine event handling is such that it is not programmatically correct to reference the properties of a DataWindow control or DataStore instance in code until this event has fired.

    The DataWindowControl class extends System.Windows.Forms.Control and therefore inherits quite a few events shared by the common user interface controls. Instead of having a Clicked event as in PowerBuilder, you will see a Click event that fires in the expected manner, and similarly for DoubleClick and the various mouse-related methods including drag-drop activities. For these inherited events, you'll notice that the argument structure is rather void of information from a DataWindow perspective, where you are used to receiving row, column, and sometimes even additional information.

    Overloading these built-in events with new DataWindow-specific event structures or creating additional but similarly named events would have been confusing for a .NET programmer; therefore, the information is obtained via a property on the DataWindowObject, ObjectUnderMouse. This property captures information that you're accustomed to obtaining in PowerBuilder using the GetObjectAtPointer and GetBandAtPointer methods; however, instead of a tab-delimited string, the object information is contained in a structure and a class instance that contains the properties of the specific object selected.

    Figure 4 shows the class hierarchy that implements the ObjectUnderMouse functionality. The DataWindow band information and row number are properties of the ObjectAtPointer structure, but more detailed information is contained in the Gob (short for Graphic Object) property. Note that the GraphicObject class is abstract, reflecting the fact that the actual runtime class of the Gob property will depend on which specific DataWindow object was encountered. If you click on a label in the DataWindow control, the actual class of the Gob property will be GraphicObjectText; however, if it were a column you selected, you would obtain an instance of the GraphicObjectColumn class instead and be able to access the column number from within it as demonstrated in Listing 2.

    With this code in place, whenever one of the column objects in the dwDepartment DataWindow is clicked on, a message box will be displayed (see Figure 5). (We'll create a version of a DataWindow object that you can try this code out on in Part 2.)

    As you can see from the class hierarchy in Figure 4, only the GraphicObjectColumn descendant class currently contains any additional information; however, this class structure paves the way for a future release to add additional properties to each of the GraphicObject descendant classes, ultimately resulting in "dot-notation" functionality similar to that which became available in version 5 of PowerBuilder.

    One of the more noticeable differences that an experienced PowerBuilder developer will discover when programming in the .NET world is the pervasive use of exceptions. None of the PowerScript functions that operate on a DataWindow control (or on a DataStore or DataWindow children) are exception enabled and instead typically return a value of -1 when a failure is detected. In .NET most DataWindow and DataStore methods will throw one or more exception types depending on the nature of the failure in the method processing. Table 1 includes a partial list of the exceptions as of this writing. Refinements continue to be made so you can expect the exceptions raised by the released version of the product to differ at least slightly.

    Many of the exceptions shown in Table 1 extend built-in classes derived from System.Exception. For instance, InvalidColumnException and InvalidRowNumberException both extend System.ArgumentOutOfRangeException, thus allowing .NET developers to handle the DataWindow exceptions at varying levels of granularity.

    In this article, we looked at the overall architecture of DataWindow.NET. In Part 2 we'll develop a sample application that contains two DataWindows with a master-detail relationship.

  • More Stories By Jim O'Neil

    Jim is a Technology Evangelist for Microsoft who covers the Northeast District, namely, New England and upstate New York. He is focused on engaging with the development community in the area through user groups, code camps, BarCamps, Microsoft-sponsored events, etc., and just in general serve as ambassador for Microsoft. Since 2009, Jim has been focusing on software development scenarios using cloud computing and Windows Azure. You can follow Jim on Twitter at @jimoneil

    Comments (0)

    Share your thoughts on this story.

    Add your comment
    You must be signed in to add a comment. Sign-in | Register

    In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.