I wrote yesterday about the WPF Snap-To Behavor that I created, and showed you how simple it is, but I skipped over where the magic happens, so I thought I’d go through how I created the Native Behaviors collection class, because there are a few cool tricks in here that I wanted to share with WPF developers at large (even if you’re not interested in hooking the Window Procedure).
The framework for Native Bahaviors is made up of just two classes, the first of which is basically 3 lines of code.
NativeBehavior is the abstract base class for behaviors, and consists of just definitions for the mandatory abstract GetHandlers() method (where you return an IEnumerable collection of mappings from Window Messages to your delegate methods) and the two optional (virtual) methods AddTo and RemoveFrom which are called when your behavior is initially added to a window (generally before the Window is initialized).
NativeBehaviors is an ObservableCollection of NativeBehaviors, obviously
. But it’s ever so much more than that. First of all, it has the NativeBehaviors attached property, but it also has the code for actually hooking a WPF window to get the Window Messages, and a WndProc which processes each message against the mappings retrieved from the various NativeBehaviors that have been registered.
Lets start with the attached dependency property. There’s a very clever (and problematic) trick in the way this property is exposed. If you look at this code, you’ll see I create a private NativeBehavior dependency property, and then create public Get/Set accessors for “Behavior” which just call the NativeBehavior property. The reason for this is that if the dependency property is public, or if the public accessors even have the same name … the XAML parser finds the dependency property and uses it directly (bypassing the get/set accesors), which means you have to have an extra element in your XAML markup to initialize the NativeBehaviors collection, or you get something like this screenshot.
So instead, we hide the dependency property, and supply a getter which is backed by the dependency property. I should not that although this works great in the .Net Framework, it’s not recognized properly by all of the tools (including Resharper 4.1 and even Expression Blend), so you may have to fiddle with things.
There’s a little more to it in the actual class source code, I’m glossing over the simplest parts, and leaving out all the XML documentation comments too. We override the CollectionChanged event so that we can hook new Behaviors as they arrive, and we make sure to hook the WndProc whenever the Target Window is set:
And finally, the last part of the puzzle is my actual WndProc implementation, which has a minor drawback in that we can hypothetically have multiple behaviors which process the same window message … and may each return a different value (which we cannot reconcile). For now I’m just returning the last (non-zero) result (in actuality, all of the behaviors I’ve written thus far return zero).
That pretty much covers the framework. The actual behaviors can be fairly simple like my Snap-To behavior (which is actually too simple), or extremely complex like my latest behavior, which is a port Joe Castro’s custom Window ‘Chrome’ to my behavior framework, and I’m hoping some of you will choose to write new ones and submit them as patches to the CodePlex project (for now, I’m just piggybacking it on the PoshConsole project). But in any case, the latest code is available via subversion on CodePlex, and you can download today’s snapshot here.
While working on my WPF PowerShell console, I’m working on implementing PSRawUserInterface, and had to implement a method called ReadKey which returns a KeyInfo object. KeyInfo is a pretty simple struct class with four properties:
So it doesn’t seem like it would be a real problem … just handle the KeyDown event or PreviewKeyDown event on the WPF control, right? Well, no. Because all of these just use a KeyEventArgs parameter which has a Key property which doesn’t map to a virtual key code (why isn’t the WPF Key enumeration in the right order? It’s ridiculous), and there’s no character information at all.
Thankfully, it is possible to get this information using PInvoke, but I wouldn’t want to try to do this in Silverlight.
Here’s how it goes:
First, you need to get the VirtualKey code. Thankfully, there’s a simple class called KeyInterop, which exposes a static method VirtualKeyFromKey that gets us this information.
Then, we need to get the character. This is much trickier. First we have to get the keyboard state and then we have to map that VirtualKey we got in the first step to a ScanCode, and finally, convert all of that to Unicode, because .Net doesn’t really speak ASCII
The rest of the code is pretty clear, I hope… Read the rest of this entry »