Categories
NETCF

OpenNETCF.Windows.Forms.Control2 in SDF 2.0

In SDF v1 I wrote a class called ControlEx which would allow you to host a native windows control within a managed Control. This was the subject of an MSDN article (of which much of the concept applies here too). The implementation was rather convoluted to work around the limits of .NETCF v1.0, and the control was constructed with a Control, which hosted a MessageWindow with some of it’s style bits altered which in turn hosted the native control. Luckily hosting controls is easier in NETCF v2.0 but unlike the desktop this functionality is still not built into the base Control class. Which is where Control2 enters the stage.


Like several other classes throughout the SDF the name has been changed to use the 2 suffix, but there are a few other changes I want to draw your attention to. First the inevitable disclaimer, what I’m going to describe won’t work with the current Beta release, as I was building the sample code for this post I realised there were a few “nice” features lacking to add a bit more reusable functionality into the Control2 class itself. So lets proceed with how the architecture has changed, and then work through specifics with a sample.


The fundamental feature in .NETCF v2.0 which enables the new architecture is the ability to marshal a managed function as a function pointer to native code. Using this we are able to handle our wndproc in a managed method, this removes the need for the MessageWindow class. Control2 is derived from Control and when added to a form it hooks up a method to process its own windows messages. These are passed to a virtual WndProc method which can be overridden in a derived control to handle specific messages. After this is hooked up the CreateControl method is called, this takes the window class details returned from CreateParams and creates the window as a child of our Control2. This means than in it’s simplest form you only need to override CreateParams with a valid class name to host your control.


However Control2 provides only basic functionality to interact with this class – for example automatically resizing when you resize the managed control, and getting/setting the control text. Beyond this you have two ways to interact with the control – add your own properties and methods to your Control2 derived class and from these send windows messages to the native control, and secondly add your own handlers for incoming messages from the control to create events.


For a basic example I’ve wrapped the CAPEDIT control which is part of WindowsMobile – this is simply a textbox which can Automatically Capitalize The First Letter Of Every Word. Because CAPEDIT is a common control it requires a call to InitCommonControlsEx – there is a static helper method in Control2 to help with this:-


Shared Sub New()


   Control2.InitCommonControls(&H2000)


End Sub


By the way as you’ve probably noticed, this and the rest of the example are in VB.NET, I would hope that it is self-explanitory enough for you to apply to C# as required.


Interestingly we don’t need to worry about the constructor for the control at all, as we don’t do anything special. Where the magic happens is in our override for the CreateParams property:-


Protected Overrides ReadOnly Property CreateParams() As OpenNETCF.Windows.Forms.CreateParams


   Get


      Dim cp As CreateParams = MyBase.CreateParams


      cp.ClassName = “CAPEDIT”


      Return cp


   End Get


End Property


And that’s it, all we did was change the ClassName in this case. The other parameters such as size are already set for you based on the current size of your managed control.


So as I alluded to earlier, the example is a very simple class so there aren’t any events to show you, just a couple of properties which are implemented like so:-


Private allcaps As Boolean = False


Public Property UpCaseAllWords() As Boolean


   Get


      Return allcaps


   End Get


   Set(ByVal value As Boolean)


      Dim val As IntPtr


      If (value) Then


         val = New IntPtr(-1)


      End If


      Dim m As Microsoft.WindowsCE.Forms.Message = Microsoft.WindowsCE.Forms.Message.Create(Me.childHandle, 1025, val, IntPtr.Zero)


      Microsoft.WindowsCE.Forms.MessageWindow.SendMessage(m)


      allcaps = value


   End Set


End Property


The magic value of 1025 was determined from the commctrl.h header file. I should proobably have created it as a const with the same name as the native implementation. One of the great things about VS2005 is that when you build a project with such a control in it, you’ll get an automatic addition to your toolbar for it. We haven’t added any designer support (outside the scope of this article) but you can set descriptions, categories and the toolbox icon for the control in the usual way. By default you’ll get a rectangle with the name of the control which you can position on your form, in many cases this might be good enough. The sample project shows the control dropped on a form with a couple of checkboxes to toggle the properties. Also as a sanity check there is a button labelled Copy which copies the text value from the native control to a regular TextBox – remember we didn’t write any code to do that, it’s built into Control2 (well in a post-Beta release at least!). The standard behaviour of the CAPEDIT control is to have no border, but you can change this by setting the BorderStyle to BorderStyle.FixedSingle for a plain 1-pixel border.


Control2Example.zip (9.07 KB)


Wait what have I missed, oh yes there are two other useful properties – DesignMode allows you to check if your control is currently in a designer so you can for example not call device specific code, and ModifierKeys is a static property which gives you the current state of the Shift/Ctrl/Alt modifier keys, if your device has a “proper” keyboard.


Stop Press:-


Exhibit A – A CAPEDIT control in a managed app:-

By Peter Foot

Microsoft Windows Development MVP