« June 2002 | Main | August 2002 »

July 31, 2002

Standard mouse event sequences for single and double clicks.

The mouse event sequence is MouseDown, Click, MouseUp. The Click is triggered by the release of the button and will occur even if the mouse moves while the button is pressed.

A double click is a MouseDown, Click, MouseUp, MouseDown, MouseUp event sequence. The second click is converted into a double click event presumably. Key to note that an initial Click event still occurs.

Event handler patterns.

Adding an event to a control is simple. The easiest case is if you can reuse an existing EventArgs class (and therefore also its delegate declaration). e.g.

class MyControl : … {

      public event EventHandler MyEvent;

      protected virtual void OnMyEvent(EventArgs e) { if (MyEvent != null) MyEvent(this, e); }

}

Raise the event at one or more places in MyControl’s code by calling:

OnMyEvent(new EventArgs());

Declare a event handler for the event in client code:

      void MyClientEventHandler(object sender, EventArgs e) { …do stuff to “handle” the event… }

Attach the event handler to the event from client code by:

      myControlObject.MyEvent += new EventHandler(this.MyClientEventHandler);

 

Observations:

1.       The “event” keyword causes the compiler to declare a private member of the given type (which must be a delegate type) and += and -= operators for registering and unregistering methods with the delegate.

2.       An event is raised (a delegate is invoked) by using the event (delegate) name as a method name.

3.       The pattern of declaring a virtual OnEvent method makes it easy to raise the event and allows derived classes full control around event raising.

4.       There are two patterns for events: event fields and event properties. The method described above is the event field method and is less storage efficient (each event has its own object for managing attached delegates) than the event property method (example below) which allows for shared storage of event delegates. The EventHandlerList class is used by the Component class Events property.

 

   public class OptimizedEventButton: Control {

 

      // Defines a key for storing the delegate for the Click event in the Events list.
      private static readonly object ClickEvent = new object();

 

      // Defines the Click event using the event property syntax.
      // The Events property stores all the event delegates of a component as name/value pairs. 
      public event EventHandler Click {

 

         // When a user attaches an event handler to the Click event 
         // (Click += myHandler;), the add method adds the handler to the 
         // delegate for the Click event (keyed by ClickEvent in the Events list).
         add { Events.AddHandler(ClickEvent, value); }

 

         // When a user removes an event handler from the Click event 
         // (Click -= myHandler;), the remove method removes the handler from the 
         // delegate for the Click event (keyed by ClickEvent in the Events list).
         remove { Events.RemoveHandler(ClickEvent, value); }
      }

 

      // Invokes delegates registered with the Click event.
      protected virtual void OnClick(EventArgs e) {
         // Retrieves the event delegate for the Click event from the Events property (which stores
         // the control's event delegates). You must cast the retrieved delegate to the type of your 
         // event delegate.
         EventHandler clickEventDelegate = (EventHandler) Events[ClickEvent];
         if (clickEventDelegate != null) clickEventDelegate(this, e);
      }
   }

 

 

Instead of EventArgs, a class derived from EventArgs can be used. In this case a new delegate type must be defined that uses the new event arg class.

For MyEventArgs, the delegate would be:

      public delegate void MyEventHandler(object sender, MyEventArgs e);

2002-07-23 18:22 Tue, dotNET, Event Handler pattern in custom controls

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/observerpattern.asp?frame=true

July 29, 2002

DataGrid bound to ArrayList and System.Array, CurrencyManager handles consistency not formatting

DataGrid’s can trivially be used to display ArrayLists by setting the DataSource property of the grid to the ArrayList object, just remember that the objects in the list must have public properties.

CurrencyManager has to do with keeping bindings current not with formatting cash.

To use column styles with a System.Array DataSource, the DataGridTableStyle.MappingName property must be set to the type name of the array. i.e. “DataItem[]”. The value to use can be seen after setting the DataSource of the grid from the debugger by looking at the protected ListManager property’s BindType.Name value.

 

Remember: ArrayList of structs has value semantics.

Remember structs have value semantics, therefore an ArrayList of structs won’t support += operators, the indexer returns copies, and changes need to be assigned back to the ArrayList.

July 25, 2002

Namespaces & WebServices

Be sure to keep the project default namespace (project properties) in sync with the declared “namespace”. Specifically, when web references are added to the project, they appear in the default project namespace.

WebServices and Exceptions, SoapException

dotNET's implementation of webservice exception passing seems to be incomplete. SoapException details don't seem to work. Nor do the internal and base exception methods.

July 24, 2002

Control Rendering

Learned:

1. Set the control’s Region property to get a non-square clipping region.

2. Parent gets painted first, leaves clipping region of all contained controls untouched.

July 22, 2002

HTML viewer using AxWebBrowser and IHTMLDocument2

To send a string to the web browse control, you may want to go through the steps below:

1. Add a reference to the Microsoft HTML Object Library.

2. When form loads, use AxWebBrowser.Navigate method to navigate to "about:blank". (This way a new HTML Document is created.)

3. Make sure the document is loaded. (The DocumentCompleteEvent shows this.)

4. Get the AxWebBrowser.Document object and cast it to mshtml.IHTMLDocument2.

5. Set IHTMLDocument2.body.innerHTML property to the HTML string.

July 19, 2002

SQL identity columns and SCOPE_IDENTITY vs. @@IDENTITY, Rowguids

Use SCOPE_IDENTITY() instead of the @@IDENTITY system function if there’s any chance of a trigger doing an insert to a table with an identity column in the interval. Identity columns complicate replication.

Rowguid’s are easier for replication. Since there’s no SCOPE_IDENTITY() equivalent, pre-allocate new guids for subsidiary table inserts.

Getting started with DataAdapters, DataSets, DagaGrids

sqlDataAdapter is a conduit between SQL server and a DataSet. A DataGrid binds to a DataSet; doesn’t know a thing about sqlDataAdapter.

The capability of TEXT type sqlCommands has certain limitations. Can’t assign @@IDENTITY to a parameter.

Set the DefaultValue property of a DataSet’s columns to avoid “doesn’t allow null” errors. Use System.Guid.Empty for rowguids.

 

When a DataGrid is used to modify the data sorting it alters the underlying DataSet; which in turn modifies any other DataGrid that may share the DataSet.

Events are dispatched to all registered handlers. There is no need or capability to indicate whether the handler “consumes” the event.

July 11, 2002

Working with collections

“foreach (Foo f in bar)” will do a dynamic cast to type Foo from the type returned by the IEnumerator for bar. No compile time warning is generated if bar returns a type that might be cast to Foo, i.e. if it’s a collection of Objects.

If there’s no possibility of casting to Foo, a compile time error occurs.

With a try block around the foreach, code execution in the debugger jumps ahead to an unexpected position which the try block instead of directly to the finally block. This appears to be a bug…

 

There are tools available for generating strongly typed collections.

July 08, 2002

SelectNodes requires XmlNamespaceManager when XML Schema file has a default namespace attribute.

Visual Studio .NET will create an XML Schema file for an open xml file (see XML menu). This adds a default namespace to the root element of the xml document which has the side effect of breaking unqualified xpath SelectNodes() queries. The solution is to use a name space manager with the SelectNodes() calls. Add the default namespace to the XmlNamespaceManager and give it a prefix. Use this prefix in the xpath query string.

 

Used XmlDocument to parse an input xml file.

Used XmlTextWriter (and StringWriter) to write an output xml file.

Used Hashtable to temporarily map names to references while building simple arrays of references.

NUnit test project setup template.

A NUnit test project should be a projct of type “class library” set to run C:\Program Files\NUnit V2.0\bin\nunit-gui.exe for debugging with a command line like “/assembly:myassembly.dll”.