The Google Data Java Client APIs provide a convenient way for Java prorgams to interface with Google’s public Data APIs, for Google calendars, contacts, and many other services.

It’s such a good abstraction, however, there is no clear way of seeing the underlying XML of the feed. When debugging, and for their interest, programmers may wish to see this data – it’s supposed to be human-readable after all.

After at least an hour of playing around I found the commands to enable the logging in the client’s initialization. Traffic will then be output to the console at run time.

The gotcha is that enabling verbose output on Java’s logging requires not just the logs to be set to Level.ALL, but also the underlying handlers.

Here’s the code.

  1. import java.util.logging.Logger;
  2. import com.google.gdata.client.http.GoogleGDataRequest;
  3. import com.google.gdata.client.http.HttpGDataRequest;
  1. Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).getParent().getHandlers()[0].setLevel(Level.ALL);
  2. Logger.getLogger(GoogleGDataRequest.class.getName()).setLevel(Level.ALL);
  3. Logger.getLogger(HttpGDataRequest.class.getName()).setLevel(Level.ALL);

Consider a function that collects and returns a list of results. It might look like this:

  1. public ArrayList<String> retrieveAll(long requesterId);

Or even better, this, so it could use anything that implements Iterable<>:

  1. public Iterable<String> retrieveAll(long requesterId);

However, storing the results in a container which is then returned may be inefficient for the application. It may be better to enable the calling code to act immediately on each collected result rather than first waiting for all results to be collected and stored. If that were possible..

  • No memory would be used to store a list.
  • Results could be presented to the user straight away.
  • Calling code could abort the collecting process part way through based on its own logic – for instance if it already has more results than it can handle.

Custom iterators

One way to avoid an intermediate list is for the collecting function to construct a custom Iterable<> object, which constructs Iterator<> objects that contain the collecting logic. Each execution of next() calculates the next value and returns it straight away for the calling code.

The difficulty for the programmer is that this may require a significantly different structure of the collecting code. This code has to store any state from result to result as private variables inside the iterator. Call stack is reset with each result, so algorithms that use recursion are not possible.

More convenient for the programmer would be a technique that allows the collecting code to keep control of the machine state during the collecting process.

Yield return

C# has ‘yield return’ which allows a function to be structured exactly as if it is building a list. It may keep its own state in local variables and the call stack, but still present each value to the calling code immediately as it is found.

Java doesn’t have yield return, but another pattern that could be used is this:

  1. public void retrieveAll(long requesterId, ResultProcessor<String> collector);

Where ResultHandler<> is a simple interface to an object invoked by the collecting code to return individual results as they are collected.

  1. public interface ResultHandler<T> {
  2.   void handleResult(T value) throws CollectionAbortedException;
  3. }

It is left up to the calling code what ResultHandler<> implementing object to supply, and how to handle the data. Anonymous classes would be quite neat here. For instance, a caller could output the results to a console like so:

  1. retreiveAll(myId, new ResultHandler<String>(){
  2.   public void handleResult(String value) {
  3.     System.out.println(value);
  4.   }
  5. });

The collect() function may abort the collecting operation part way through by throwing a CollectionAbortedException.

The disadvantage to this approach is that it is a little less convenient from the perspective of the calling code. The function has a novel pattern, taking ResultHandler<> as a parameter rather than the more familiar Iterable<> as a return value.  Logic has to be embedded inside an anonymous or specially constructed ResultHandler<> class.

Unlike the case of returned Iterables, the calling code can not use ‘for each’ loops on the result. Nor can it store or pass around the Iterable<> to other systems as a parameter.

Solution : The yield adapter

A best-of-both-worlds solution would allow a collecting method based on ResultHandler<> to be automatically adapted at run time to an implementation based on Iterable<>. A data-collecting function implemented in this form (convenient for the collecting code) …

  1. public void retrieveAll(long requesterId, ResultHandler<String> collector);

.. would be adapted into this form (convenient for the calling code)..

  1. public Iterable<String> retrieveAll(long requesterId);

This would provide the same benefit C# programs get from yield return. Namely, the ability for both collecting code and calling code to have their own machine state and callstack control throughout the entire collecting and processing operation. It is not necessary for either side to separate logic into methods inside anonymous classes. Collecting code can use complex recursion algorithms. Calling code can store and defer use of the Iterable<> used to collect results, or pass them as parameters to other functions.

Approach Collector controls flow Caller controls flow Requires list Caller can abort collect Uses new thread
Collector builds and returns list in form of Iterable<> yes yes yes no no

Collector returns Iterable<> containing logic

no yes no yes no
Caller passes in ResultHandler<> yes no no yes no
ResultHandler<> wrapped to Iterable<> with yield adapter. yes yes no yes yes


How it works

I am not the first engineer to attempt to bring yield to Java. Aviad Ben Dov’s article in 2007 http://chaoticjava.com/posts/java-yield-return-code-published/ describes a way to do this using bytecode manipulation and classloader modification. My view is that a solution in Java alone would be more practical as a portable library.

My starting premise was that if calling code and collecting code are both to have their own call stack, this could only be achieved with the use of multiple threads.

In addition, I was aware of a Java collection SynchronousQueue which is designed to allow two threads to pass values between each other, each in turn yielding control to the other.

The Yield Adapter simply makes a new custom Iterable<> which is returned to the calling code. The iterable creates iterators on demand, which also starts a new thread for the collection, and makes a SynchronousQueue for communication between the two. Results are wrapped in message object and, .put() into the queue on the collecting side. The iterator side uses .take(). There is also some extra logic to ensure that incomplete reads do not result in leaked resources.

Please note that although the adapter uses threads, the code does not normally need to be ‘thread safe’ in the classic sense. That is because there is never a time that both threads are executing simultaneously. One thread always ‘yields’ to the other. The exception to this is if multiple iterators were ever in effect at once.

Source and demos

The adapter source can be found here with the interfaces employed all here.

A demo here shows how the adapter can be used to allow a recursive scan of files and directories, returning the result through an iterator.

A more complex demo here returns all possible ways the letters in a word can be rearranged, without repeats.

The library source can be downloaded with Subversion or your browser here and the tests and demos are here.

Feedback

I hope that this small library will allow people to develop complex algorithms that present results to calling code as iterators.

If you have any comments on the code, please add them as comments on this article.

Update Feb 2009

Many thanks to Dominic Lachowicz who brought to my attention the fact that the SynchronousQueue does not in fact stop both threads running at the same time. A revision checked in today uses a Semaphore object to achieve the desired behaviour.

A project I’ve been working on required a random selection of postings to be shown to users. The entries were to be drawn from a larger list : a cache of references to posts held in memory.

My first effort at the selection code simply copied the original list, shuffled it, then selected the first ‘n’ entries (where ‘n’ is the number of required postings). A colleague remarked that this was hardly an optimal use of time or memory. So I decided to write a a general-purpose function to select ‘n’ unique entries from a list of ‘m’ entries – using as little memory and processing time as possible.

A naive solution

The most obvious solution to the problem is to repeatedly draw random entries from 0.. n of the list. To reduce the repeats, keep a record of the indices of the random entries already selected. Then, as each new item is selected, the existing list is checked to see if the entry was already taken.

The problem with this is that as more entries are selected the likelihood of such a collision increases. The execution time of the function cannot therefore be predicted. In some cases where the number to select was very large this could make the function quite slow. You could speed it by using different containers and such, but a better approach seems to be avoid collisions in the first place.

Consider a case of selecting five random entries from a list of ten. The first entry index can be found by picking a random number between zero and nine. When making the second selection however there are now only nine remaining unselected entries. So if we pick from zero to eight, then find a way of converting this number (the index of unused entries) into a full source table index, we have avoided the possibility of collision altogether.

The method

My solution calls for items chosen using a random number generated between 0 and m-c where ‘c’ is the number of already selected items. This represents the relative index of unchosen entries, not the actual entries themselves. This number is then converted into the actual entry index by an algorithm.

This algorithm involves iterating backwards through the list of already picked random numbers. The principal is at each iteration to convert the index from 0… m-c space to 0 .. 1+m-c space. In other words the space of the previously selected element. One single operation can do this, and at the same time avoid any potential collision with the last drawn entry in its target space. The operation says “if the already selected entry’s unchosen entry index is the same or less than the current index number then increment this index by one.”

When all already selected entries have been processed in this way, the resulting index is guaranteed to be in 0.. n space and clear of any collisions with already selected entries.

The method has an order of execution n*m / 2, and temporary storage requirements of n indices. This is stable and predictable however so it is a in improvement on collision avoidance methods that would mean repeating random selections.

Code

Here is a ready-to-use implementation in Java.

  1. import java.util.List;
  2. import java.util.Random;
  3. import java.util.ArrayList;
  4.  
  5. public class ListUtil {
  6.  
  7.     /**
  8.      * Create a new list which contains the specified number of elements from the source list, in a
  9.      * random order but without repetitions.
  10.      *
  11.      * @param sourceList    the list from which to extract the elements.
  12.      * @param itemsToSelect the number of items to select
  13.      * @param random        the random number generator to use
  14.      * @return a new list   containg the randomly selected elements
  15.      */
  16.     public static <T> List<T> chooseRandomly(List<T> sourceList, int itemsToSelect, Random random) {
  17.         int sourceSize = sourceList.size();
  18.  
  19.         // Generate an array representing the element to select from 0... number of available
  20.         // elements after previous elements have been selected.
  21.         int[] selections = new int[itemsToSelect];
  22.  
  23.         // Simultaneously use the select indices table to generate the new result array
  24.         ArrayList<T> resultArray = new ArrayList<T>();
  25.  
  26.         for (int count = 0; count < itemsToSelect; count++) {
  27.  
  28.             // An element from the elements *not yet chosen* is selected
  29.             int selection = random.nextInt(sourceSize - count);
  30.             selections&#91;count&#93; = selection;
  31.             // Store original selection in the original range 0.. number of available elements
  32.  
  33.             // This selection is converted into actual array space by iterating through the elements
  34.             // already chosen.
  35.             for (int scanIdx = count - 1; scanIdx >= 0; scanIdx--) {
  36.                 if (selection >= selections[scanIdx]) {
  37.                     selection++;
  38.                 }
  39.             }
  40.             // When the first selected element record is reached all selections are in the range
  41.             // 0.. number of available elements, and free of collisions with previous entries.
  42.  
  43.             // Write the actual array entry to the results
  44.             resultArray.add(sourceList.get(selection));
  45.         }
  46.         return resultArray;
  47.     }

An SVNWatch desktop alert

Part of my last job involved some management of a large code base. I wanted to keep an eye on activity on the Subversion source control database. In particular I wanted to know as soon as someone had checked in and what the changes were.

There are many plug-ins available for Subversion (also known as SVN) that will email interested parties when the repository changes, but my experience with these is that they create so many emails that people end up turning them off. Also, they need administrator access to the database which not everyone will have.

I hit on the idea for a “notifier” application for Subversion that would act like the gmail notifier, letting interested parties know as soon as an SVN database is changed. The Windows balloon alerts are ideal for this sort of thing, so I wrote an application for Windows Forms .NET 2.0 which I am ready to publish today.

SVNWatch

SVNWatch is a Windows application that provides desktop alerts when nominated SVN repositories are changed.

The application runs in the status bar. Alerts when the repositories change take the form of messages in status bar ‘balloons’, and a change in the appearance of the status bar icon.

Clicking on the status bar icon will display a list of the new SVN log entries since the last scan operation.

The application can watch an unlimited number of SVN repositories.

Prerequisites

SVNWatch requires two other components to be present on the user’s PC:

  1. The .NET Framework version 2. Vista comes with this pre-installed. For XP, this can be downloaded from the Microsoft website here.
  2. The Subversion Windows client software (“SVN.EXE”). This can be downloaded from the Tigris/Subversion website here.

    This is required because SVNWatch invokes the SVN.EXE to interface with the repositories, rather than using an internal static library. I had poor results getting the same results out of the standard API that are available through the SVN.EXE route.

The main dialog

The main dialog lists the watched repositories, provides options to manage the list and gives information about forthcoming scans.

The main SVNWatch window

Click on the ‘Add Repository’ toolbar button or from the Repository menu select Add.

A New Repository dialog will be shown. Under Monitor Url enter the URL of the repository, for instance http://svn.jimblackler.net/jimblackler/trunk.

Click OK to add and start monitoring the repository.

First time connection

SVNWatch will fetch and display the first batch of logs. If there is a technical problem connecting to the repository or fetching the logs, this will be displayed in the bottom of the main SVNWatch dialog.

Regular scans

As long as SVNWatch is running, it will regularly scan repositories for new logs
to report. The frequency of scans can be changed in the Settings.

When new logs are available a notification balloon will be shown in the task bar. If just one new log is seen, a quick summary of the check in comments will be shown. If more than one log is available, the number of logs available will be shown.

An alert just displaying the number of logs received

Clicking on the bubble will show a full and detailed list.

A full list of new logs

In addition, the task tray icon will change to indicate there are new logs that have not been viewed by the user.

If new logs are available, they can also be viewed by clicking on the View New Logs button.

Edit repository settings

Repository URLs or other settings can be edited at any time by selecting the repository in the main list and selecting Edit Repository.

The user can also view when the last scan was performed and what the outcome was. This can be useful for troubleshooting problems to do with database connection.

The Maximum Fetch value indicates the largest number of logs to download. This is necessary because some long-established SVN repositories are very large.

Settings

Settings, which include the repositories scanned, are automatically saved and retrieved. They are stored for each Windows user.

The settings file can be found in a location such as C:\Documents and Settings\User Name\Application Data\SVNWatch\settings.bin where User Name is the current logged in Windows user name.

The settings can be edited by selecting the Edit menu then the Settings menu item.

The settings dialog

  • Minimise to tray
  • When the application is not in use it is only shown in the system tray, not the taskbar.

  • Scan every
  • The interval in which to scan each SVN repository for changes.

  • Time out
  • The amount of time to wait for remote operations to complete before giving up.

  • Run on startup
  • When checked, the program will start running as soon as the user logs into Windows.

Download

Download SVNWatch as an executable installer from here. Before running SVNWatch, go to the Tigris official Subversion website and download and install the Windows Subversion client (used by SVNWatch).

Alternatively, you may obtain the source code from my own SVN repository here. The project can be built with Visual Studio 2005 C# Express or other later versions of Visual Studio. SVNWatch and its dependent projects are open source, licensed under the LGPL.

C# .NET provides a standard mechanism for programmers to inline XML documentation in their programs. Classes, functions, properties and more can be augmented with comments, and the build system creates amalgamated XML files accompanying the program output. A variety of tools such as Sandcastle can build help files from the data. Visual Studio 2005 and 2008 also supports the scheme with keyboard shortcuts and optional build warnings for missing comments.

  1. /// <summary>
  2. /// An example C# class
  3. /// </summary>
  4. /// <remarks>
  5. /// This class illustrates how a class can be marked up with inline C# comments
  6. /// </remarks>
  7. class SomeExampleClass
  8. {
  9.     /// <summary>
  10.     /// An example of a property
  11.     /// </summary>
  12.     public int ExampleProperty
  13.     {
  14.         get { return somePrivateVar; }
  15.     }
  16. }

Unfortunately, many programmers have observed that there’s no way to discover these comments at runtime by reflection. All manner of alternative information can be accessed with reflection – but not the XML comments.

The solution

This documentation can be discovered at run time with a little extra code, as I will demonstrate. The reason the comments can’t be discovered by reflection alone is because they are not included in the .NET assemblies (.EXE or .DLL files), but are conventionally included as .XML files to accompany the assembly files.

I’ve provided a simply class library for .NET 2.0 called DocsByReflection that will when possible return an XmlElement that describes a given type or member. This can be used to easily extract comments at runtime. Here’s an example of how:

  1. XmlElement documentation = DocsByReflection.XMLFromMember(typeof(SomeExampleClass).GetProperty("ExampleProperty"));
  2. Console.WriteLine(documentation["summary"].InnerText.Trim());

This would ouput “An example of a property”, extracted from the code comments in the code fragment at the top of the article.

The class works by locating the .XML file accompanying the assembly that defines the type or member (discovered using reflection). Then the .XML file is loaded into an XmlDocument, and the ‘member’ tags are scanned to find the one that refers to the target type or member. This tag is returned as an XmlElement which contains the free form XML that these comments can contain (e.g. including HTML markup).

This method relies on the existence, on disk, of the generated XML. It must have the same name and location as the generated .EXE or .DLL accompanying it – with only the extension changed. This will happen by default when building with Visual Studio, once documentation is enabled (see below). If you are distributing your program and expect the distributed version to discover the comments in run time, you must also distribute the XMLs alongside the executables. This is commonly seen in any case. Note that many of the framework executables (for instance those found in C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727) are accompanied by documentation XML files.

How to use

Download the library source as a zip file here, or use Subversion to update to the very latest version here and here.

(Updated 18/3/08 for bug fix – see comments).

Load the DocsByReflectionDemo.sln to see a simple example of how to use the library. This gathers and prints information about a class type, some functions, a property and a field.

Using in your own code

In Visual Studio, set up your own project that includes XML comments.

(Note that the XML documentation output is not enabled by default in Visual Studio. Go to your project properties, select Build, and under the Output section check the box that says XML Documentation File. It is very important that you do not change the location of the XML file or this method will not be able to locate it at run time.)

If you have not already, add the comments in Visual Studio. By default, pressing forward slash three times when the caret is positioned before the start of an element you wish to document (such as a class or method) will insert a documentation template for you before the start of the file.

Add the DocsByReflection project to your solution and a Reference to it from your project. Add the line “using JimBlackler.DocsByReflection;” to the top of your .CS file. The call se the functions DocsByReflection.XMLFromType() (for classes, structures and other types) and DocsByReflection.XMLFromMember() (for methods, properties and fields) to fetch XmlElement objects that represent the documentation for that type or member.

Query the returned object to read the documentation. For instance, xmlElement[“summary”].InnerText.Trim(). This locates the summary node, and uses the InnerText property of XmlElement to strip out any XML formatting that may be embedded in the comment. Also, Trim() or a regular expression can strip the unwanted whitespace from the comment.

Comments or problems

If you have any comments or problems with the library, please add a reply to this blog post and I will answer them here.

A simple application overriding enter and return in a TextBox

Many applications feature text input boxes that used to accept input for immediate use by the program. For instance, a program might provide a dialog allowing user to search for text in a document. This would feature a text box to enter the text, and a button next to it labelled ‘search’ that would immediately act on the supplied text.

However many users will not want to click the ‘search’ button, but simply press Return or Enter after entering the text.

How can this be done in a C# .NET 2.0 Windows Forms application? One way is to set the Accept property in the parent form to refer to the ‘search’ button. This will make Enter / Return automatically press the button, when pressed in any child control on the form.

The events to override in the designer

This doesn’t always offer the level of control the application developer wants. Any control could activate the press, not just the relevant text box. It requires a button, which might not always be desirable. Also it is not trivial to allow multiple textboxes on a single form that all accept Enter / Return in that way.

The best way that I have found is to add a KeyDown event to the textbox and compare the pressed key with Keys.Enter. Then, act on that key and set SuppressKeyPress in the event arguments so that the system does not try to do anything further with the keypress. (Typically what happens otherwise is that an ‘error’ beep is played).

  1. private void textBox1_KeyDown(object sender, KeyEventArgs e)
  2. {
  3.     if (e.KeyCode == Keys.Enter && e.Modifiers == Keys.None)
  4.     {
  5.         // do something with textBox1.Text
  6.         e.SuppressKeyPress = true;
  7.     }
  8. }

However if you implement that code and run the application, you’ll find nothing happens when you press Enter. The reason is that the Enter key press never reaches the KeyDown event. This happens because certain key presses are reserved for system use. The solution is to supply a PreviewKeyDown event in the textbox. This gives the opportunity to override the system override as it were, and allow the key to reach the KeyDown even in the textbox.

  1. private void textBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
  2. {
  3.     if (e.KeyCode == Keys.Enter && e.Modifiers == Keys.None)
  4.     {
  5.         e.IsInputKey = true;
  6.     }
  7. }

I’ve provided source for an example application as a zip file. Requires Visual Studio 2005 or later, C# express will also work.

Download source code

Mac and Java 1.6 (or the lack thereof)

Java SE provides a great opportunity to create applications that will run on Windows, Linux and Mac from the same single .jar executable file. All the end user needs is Java installed, and this is installed as standard for many OSes.

Unfortunately at the time of writing, Jan 2008, there is a problem with targeting Macs. Even the latest version of the Mac operating system OSX 10.5 (Leapard) does not include the latest version of Java, 1.6, that has been the default in Windows-based Java IDEs for a year at least.

A beta can be downloaded but this requires registration on the developer sites, cannot run on OSX 1.4 (Tiger), requires an Intel 64 bit processor, and has other restrictions. Right now it’s far from ideal for a mainstream application, and it’s hard to imagine that even when released officially 1.6 will reach a critical mass of deployment until 2009 at least.

The Windows NetBeans to Mac problem

Unfortunately GUI applications developed with the latest Windows NetBeans 5.5 (the free Java API from Sun) require some configuration to allow applications to be developed that run on out-of-the-box Macs. This is not just because of the OSX Java 1.6 problem, but also some glitches with the “backport” targeting in NetBeans. This affects GUI applications developed with NetBeans GUI editor which uses Swing, a cross-platform GUI layer for Java.

It is not enough to set the source level to 1.5 in the project properties, but to continue to use the 1.6 JDK. This will not run on OSX with 1.5 JRE. The error in the Console will be:

java.lang.NoClassDefFoundError: javax/swing/GroupLayout$Group

The problem is that when using NetBeans’ Swing editor with the 1.6 JDK will create code that won’t run on machines that have Java 1.5. This is because it inserts references to javax.swing.GroupLayout, which only exists in 1.6 onwards. Misleadingly, it does this even if ‘source level’ is set to 1.5.

The solution

This can be fixed by downloading the 1.5 JDK (aka the Java Development Kit 5.0 Update 14) and set your NetBeans project to use it. When new Swing GUI elements are created with this JDK set, the IDE uses the org.jdesktop.layout.GroupLayout class instead. This is not built into the JRE but the additional files can be bundled in your .jar. More about this in a second.

The file you require is jdk-1_5_0_14-windows-i586-p.exe and can be downloaded from Sun. Once installed, in NetBeans select Tools->Java Platform Manager. Click Add Platform and choose C:\Program Files\Java\jdk1.5.0_14.

In your applications, in the properties panel, select Libraries, then set the Java Platform to Java Hotspot(TM) Client VM 1.5.0 14-b03 which should now be available. It is important that you do this before you add any Frames as the act of doing this generates the code that must use the correct version of GroupLayout.

The last step is to ensure that the files that 1.5 users (i.e. Mac users) will require are bundled into your .jar, follow the instructions here.

In conclusion

Following these instructions will results in a .jar file that can run on any out-of-the-box installation of OSX, Windows (with latest Java), or Linux.

A great benefit of cross-platform Java SE with Swing is that you can create applications that use all the standard “native” GUI controls for the platforms on which they run. The end-user will have little idea that Java was used, they’ll just see it as an application that looks like it was developed for their choice of OS. To make your Swing applications use native look and feel, follow the instructions under “Programatically Setting the Look and Feel” here

ASP.NET is great at separating design and code elements on the server side. This extends to a powerful yet simple way of adding your own custom controls to your ASP.NET websites.

A trackBar control for ASP.NET/Javascript

It provides a great method to connect HTML elements in an .ascx and back end server code in a .cs file. This approach is quick to get going and has long term scalability too. However, on the web today, developers will want to have the option of client side dynamic code too, in the form of JavaScript elements to add to the control.

Microsoft’s suggestions are useful but only suitable for simple applications such as mouseover effects. This is because they tell you how to add isolated fragments of JavaScript to DOM elements. I wanted a single JavaScript class that had permanent links to DOM elements.

Lately they also provide Ajax tools for ASP.NET, and a framework of Ajax controls. There are some nice controls with these tools. However even with everything installed, what you don’t get is an way of adding your own JavaScript enabled custom controls which is as easy as adding a Web User Control from the Add New Item wizard. I was expecting to see a pattern that simply provided a client side .js file to complement the server side .cs and .ascx files. The AJAX tools seem rather over-complex compared to vanilla ASP.NET 2.0, and worse still, this approach requires .dlls to be installed on the server side. I had to telephone my host to ask them to add the components.

I’ll explain the simpler system I have developed. My aims were:

  • To neatly include all the JavaScript in a .js file, containing a parallel JavaScript class for the control.
  • To give the JavaScript part access to DOM elements set up in the .ascx (server side) part of the control (either runat=”client” elements type or elements created with runat=”server” controls).
  • To give the JavaScript part access to the attributes set on the server side of the control.
  • To allow unique HTML IDs, so that there can be more than one control of that type per page, with each control operating independently.

My method enables links not only between server and client sides of a user control, but between controls and their parent elements on the client side (just as could be done on the server side). Think of it as “client-side code behind”.

How it works

  1. An ASP.NET control is set up in the usual way with code behind which adds the .ascx and .ascx.cs files to the project.
  2. The developer adds a .ascx.js file to the project for the client-side components, with a matching name.
  3. This contains a single class wrapped with a single function of the same name, and taking as parameters the client ID of the the control, and any properties that the JavaScript object requires to receive from the server-side part. e.g:

    1. function TrackBar(clientID, minimum, maximum, smallChange, barPixelWidth)
    2. {
    3. //....
    4. }

    The ClientID allows the JavaScript to have access to the DOM relating to its specific instance using the getElementById() function. This is because is possible to predict client IDs of child DOM elements by using the control’s own parent ID. For instance a div declared with <div runat=”server” id=”content”> in a control with client ID “myControl1” will have the client ID “myControl1_content”. In code this could be obtained with getElementByID(clientID + “_content”);

    The use of runat=”server” is necessary because although a static client ID could be provided, this would not have a name unique to the page, and would therefore not allow more than one control of that type per form or parent control.

  4. The developer adds two pieces of JavaScript to the .ascx. Firstly, a client-side include to the .ascx.js script:
    1. <script type="text/javascript" src="TrackBar.ascx.js"></script>

    Below that, a script to create a new instance of the JavaScript object with the expected parameters detailed in the previous step.

    1. <script type="text/javascript">
    2.     <%=ID%>= new TrackBar('<%=ClientID%>', <%=Minimum%>, <%=Maximum%>, <%=SmallChange%>, <%=BarPixelWidth%>);
    3. </script>

    The “<%=ID%> =” before the ‘new’ creates JavaScript code that sets a variable that contains the JavaScript object associated with the control that is named the same as the server side ID for the control. This could allow JavaScript in the parent page to interact with the control object of the child control.

Example

The example trackBar application.

An example with an online demo and full source is presented here. I’ve developed a TrackBar control for ASP.NET similar to the control in Windows Forms. This control is for number entry by a user viewing a web page. It presents a number as a text box, but if the user has JavaScript enabled it also shows a visual slider that can be manipulated with the mouse. The effect on the value can be seen in real time.

The control changes the text in the TextBox which gives a return path of data to the server side. An example of this can be seen in the code in the Default.aspx.cs file.

In addition, a callback can be added to an instance of a TrackBar control on the client (JavaScript) side. An example of this can be seen in the code in Default.ascx.js, where the position and content of a text fragment is changed in real time as the slider is altered.

A family member requested I write them a simple windows program to help them with some medically-prescribed breathing exercises. For the exercise (which is designed to lower blood pressure) you have to breath in for six seconds, and out again for six seconds. In the absence of a commercial timer available to do this, a dedicated timer program on PC is the next best thing. The program simply displays a bar-chart type graphic with the bars appearing and disappearing to indicate the six second intervals.

Screenshot

A tiny project like this was the perfect opportunity to take the newly-released VS C# Express 2008 for a spin. Initial impressions are good, just like Express 2005 almost everything is there for professional development. It offers both Windows Forms and WPF as options on the New Project wizard, but it seems only to offer 3.5. In other words there seems no easy way of targeting 2.0 or other .NET versions from the wizard. I can confirm that 2.0 projects do load though (after running the conversion wizard) so it must be possible.

I like the WPF designer and the massive flexibility that WPF gives the developer in UI development. For this application, it was possible to add geometric shapes to the interface, which would have been hard in the Windows Forms designer. Also it meant that the window can be set to scale when resized. Being able to switch between a massive timer display and a tiny one could be very useful for users of a program like that.

For reference, the way to have WPF content automatically scale is to wrap the content in a tag. Note that for me, this meant the designer no longer shows the embedded content which is annoying. But it does mean it automatically scales nicely at run time.

Installer for One to Six program

I’ve written a simple puzzle game based on an idea I’ve been knocking around. The idea is inspired by slide puzzles and the Rubik’s Cube. Also a lesser-known puzzle called the Rubik’s Clock that I loved as a child.

The objective is to return a grid of numbers to its original form by rotating individual 2 x 2 square bocks by 90 degrees. Hard to explain but give it a go, you’ll work it out quickly I’m sure

Number puzzle grid

The grid starts out straight. You can scramble it yourself or hit the ‘Spin’ button and have it done for you (hit it again to stop the scrambling). You can also experiment with using the slider to create grids of different sizes.

It is worth pointing out something though. When I came up with the idea I thought that it would be about as difficult to complete as a standard slide puzzle. Wrong. It seems very, very difficult. People tend to get very stuck on the last row. In fact, based on a day’s play testing, nobody has yet even completed a 3 x 3 grid.

So give it a try, you could be the first.

« Older entries § Newer entries »