Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX

By submitting your information, you agree that devx.com may send you DevX offers via email, phone and text message, as well as email offers about other products and services that DevX believes may be of interest to you. DevX will process your information in accordance with the Quinstreet Privacy Policy.


The Baker's Dozen: 13 Productivity Tips for Building a .NET Distributed Application : Page 4

The Common Ground Framework for .NET provides a set of starter classes for building database applications in a distributed environment.




Application Security Testing: An Integral Part of DevOps

Tip 6: Handling Lookup Tables that Change Periodically or Infrequently
The application uses several lookup tables (list of items, different business codes, and so on) that change once a month, or maybe a few times a year. You would waste bandwidth by constantly querying these tables to populate pick lists; however, you cannot go to the other extreme and hard-code these values in the software. I'll show you how to implement a process that will retrieve these tables at initial start-up, save them locally as XML tables, load them back into datasets at subsequent start-up, and compare datetime stamps on the server for any new insertions/modifications.

The demo application uses a pick list of possible Material Types (Slate, Fuel, Stone, Rock, etc.) for each construction job. The company might add a new type each month. To avoid retrieving the entire list every time, the system can perform a check at various times to see if any new types have been added by using a DateLastUpdated column. For instance:

  • When the user loads the application for the first time, run a stored procedure to return the material type table to a client-side dataset.
  • When the user closes the software, save the client-side dataset to an XML file on the user's hard disk.
  • When the user re-loads the software, read the XML table back into memory, and sort on DateLastUpdated (descending order) to obtain the most recent chronological date.
  • Call a stored procedure to return all rows in the Material Type table with a more recent DateLastUpdated value than the most recent DateLastUpdated on the client end.
  • Use the ADO.NET Merge function to combine the new incoming rows from Step 4 into the existing in-memory table. Since some of incoming rows from Step 4 could be updates and some could be insertions, you must define primary keys for the Merge function to work correctly.
Listing 11 contains a stored procedure for steps 1 and 4. The procedure contains a parameter for DateLastUpdated. Note the parameter is initialized to NULL, and the query utilizes the T-SQL COALESCE function. This allows you to execute the procedure with no parameters and return all rows, and also execute the procedure with a date and return only those rows that have been added/modified more recently than the parameter you supply. The calls to execute the stored procedure would be as follows.

DsMaterials = new Masonry.DataSets.DsMaterials(); DsMaterials = oMaterialObject.GetData();

You can do steps 2 and 3 on the client side.

// Step 2 DsMaterials.WriteXml("Materials.xml", XmlWriteMode.WriteSchema); // Step 3 DsMaterials.ReadXml("Materials.xml", XmlReadMode.ReadSchema); // Create view, sort on Date desc, look at top row DataView Dv = new DataView(DsMaterials.Tables[0]); Dv.Sort = "DateLastUpdate DESC"; DateTime dMaxLastUpdate = Convert.ToDateTime(Dv[0]["DateLastUpdate"]);

After you retrieve the most recent last update in step 3, you can call the same function you called in Step 1, this time with the parameter. You can call it once at the beginning of the application, or anytime you want to check for updates to the Materials file.

DsNewData = new Masonry.DataSets.DsMaterials(); DsNewData = oMaterialObject.GetData(dMaxLastUpdate);

If DsNewData contains any data, the last step is to merge the new data into the existing data.


Tip 7: Building a Statusbar Control on the Main Screen
You want to display specific system information in a status bar at the bottom of the screen.

The CG Framework contains a base MDI parent class. A developer can inherit from a base form (CGS.Winforms.Forms.cgsFrmMDIParent) to create a main MDI parent screen.

The cgsFrmMDIParent form contains a StatusBar control with three pre-designed panels to display the current user, connection, and system info (see Figure 3). The form contains a virtual method called SetStatusBar (see Listing 12) that a developer can accept as the default, or override.

Figure 3: Status bar at the bottom of the main screen.
Tip 8: Extending Windows Forms Controls
You want to subclass the main Windows Forms controls to extend behavior and establish a default appearance.

One of the first recommendations when developing with a new tool is to subclass the UI controls. Many organizations and clients have specific requirements about user interfaces, such as data entry behavior and colors. By abstracting the desired functionality and appearance into a set of subclasses, developers can deliver a solution with a consistent look and feel.

Unlike other development environments, a developer cannot subclass the Windows Forms controls visually—you can only subclass them through code. While some initially view this as disconcerting, the reality is that one spends very little development time subclassing. Additionally, the process is a good exercise in working with the language.

The CG Framework contains a set of starter classes in the CGS.Winforms.Controls namespace, as cgsControls. Let's take a look at a subclassed version of the label control.

public class cgsLabel: System.Windows.Forms.Label { override public Font Font { get { return base.Font; } set { ; } } public cgsLabel() { base.Font = new Font("Verdana",8); } }

This is a very simple example that merely sets the font to Verdana. However, it differs from the most commonly seen method for setting the default font.

// Don't use this example public cgsLabel() { this.Font = new Font("Verdana",8); }

This approach is problematic—not so much in concept as in practice in VS.NET. In the latter example, when you drop an instance of this label on a form, and you set other design-time properties of the label (such as Caption, Location, and so on), the Windows Forms designer generates code in the InitializeComponent method. This generated code includes the value for the font property.

Now suppose that your company decides to use Tahoma or a different point size. Changing the font property above will NOT change the font on all forms where the label subclass was used, because the forms use the generated code the first time any other property of the label was modified. The only workaround is to highlight all the label controls, bring up the property sheet, go to the Font control, right-click, and choose "Reset." This is (in this author's opinion) a sub-standard way of addressing the situation. Hopefully future versions of Visual Studio .NET will address this behavior.

For now, you can address this by setting the base font in the constructor and blocking the Set statement. This prevents the Windows Forms designer from generating code, and ensures that the application will always derive the font from the subclass. (This will have the opposite effect—because the Set statement is blocked off, a developer cannot override the font of a label that's used on the control. If you need this capability you should modify the behavior to support this).

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.
Thanks for your registration, follow us on our social networks to keep up-to-date