Sunday, October 23, 2011

Better, type-safe dependency properties in C#, WPF

WPF is a great toolkit for graphical user interface programming where you can truly (and easily) separate program logic from user interface.
The dynamic and flexible binding mechanism is powerful, yet easy to use (once you grasp it :D). Because of it's dynamic nature, type safety is often an issue. Even the most fundamental constructs, like declaring a property that you can use as a binding target (called DependencyProperty) requires you to use casts. Here as a simple example that declares a DependencyProperty called Number of type int:

using System.Windows;

class ProgramLogic : DependencyObject {

    public static readonly DependencyProperty NumberProperty = DependencyProperty.Register("Number", typeof(int), typeof(ProgramLogic));

    public int Number {
        get { return (int) GetValue(NumberProperty); }
        set { SetValue(NumberProperty, value); }
    }
}
As you can see, there are some constructs that you would usually avoid, such as using typeof and - the single worst construct in every programming language - a cast to int in the property's getter.
While describing this to a friend lately, we said to ourselfs: "Why did they choose this construct? C# does have Generics, so why didn't they use it? Even if it would be just a helper function or class, it'd be much better than that.". So we came up with a wrapper to DependencyProperty, which is a bit shorter, and, most importantly, does not require a cast.
class DepProp <PropertyType, OwnerType> where OwnerType : DependencyObject {

    public DepProp(string name) {
        property = DependencyProperty.Register(name, typeof(PropertyType), typeof(OwnerType));
    }

    private DependencyProperty property;

    public DependencyProperty Property {
        get { return property; }
    }

    public PropertyType Get(OwnerType owner)
    {
        return (PropertyType) owner.GetValue(property);
    }

    public void Set(OwnerType owner, PropertyType value)
    {
        owner.SetValue(property, value);
    }
}
The class DepProp (pick a better name when you decide to use it, please) uses two generic parameters. The first one is the type of the property, the second one is the owner's type, which must be derived from DependencyObject. IMHO, using generic parameters is much better than using typeof. These generic parameters are used to guarantee that later calls to Get() and Set() are called with - and return - the correct types. This way, we made the DepdencyObject.GetValue() call type-safe. Sure, the implementation still uses a cast, but what I find most important is that there are no casts spread throughout the whole project. A neat side-effect is that using this class requires a tiny little less typing than the original DependencyProperty. Another nice feature is that you don't need to call a static member function to register your dependency property. Instead, you use new, just like you would do with any other object. Here is the implementation of ProgramLogic using the new DepProp:
class ProgramLogic : DependencyObject {

    public static readonly DepProp<int, ProgramLogic> NumberProperty = new DepProp <int, ProgramLogic>("Number");

    public int Number {
        get { return NumberProperty.Get(this); }
        set { NumberProperty.Set(this, value); }
    }
}
As we can see, the required code is a little less. But the real nice thing is that the compiler can help you pointing out refactoring errors. Let's imagine that you would want to change your NumberProperty to be of type string instead of int. When you change the generic parameter of your NumberProperty declaration and initialization, the compiler would spill out an error in the "normal" property's getter and setter, because the property is still of type int.
I hope that you find this (really) small helper class useful and that it inspires you to write more code like this that makes your overall codebase more maintainable and readable.

Wednesday, July 13, 2011

GridLayout for WPF: Escape the Margin hell

Working with WPF, you surely have come across the System.Windows.Controls.Grid class. It is a derivation of System.Windows.Controls.Panel, which in turn is a base class for layouters. You can use a Grid to create windows that have their child elements arranged in a uniform manner.

When you have worked with the Grid class, you probably know about this issue: Adding elements to the Grid will make them be strung together without any spacing between them. When you want to add spacing, you have to set each element's Margin property accordingly. This wouldn't be half as bad - it's just that, depending on where in the Grid your element is, you have to set the left, top, right and bottom margins differently. This can become quite a tedious task and makes your XAML look far more complicated than it needed to be. And that's not all - imagine you putting together a prototype of a very complex UI. Just think about one of those equalizer/sound processor programs that have dozens of controls arranged in a grid. You finally finished your prototype - you think it looks awesome - and show it to your boss. His face turns to a disgusted visage and he says "Why is it all so clung together? You can barely tell the buttons apart since they are too near to each other. Can't you add more space between them?". With the standard Grid class, you would gasp, look a bit depressed and tell your boss to come again in an hour or two. And when he comes around and wants to look at your updated prototype, you are still not finished changing all the margins correctly.

Forget that scenario. Use the GridLayout class from the download below and change all margins at once. It automatically sets a uniform margin to all child elements of this specialized Grid class. And even better - it is smart enough to set the Margin.Left of elements in the first column to 0. The same goes with the Margin.Right in the rightmost column, Margin.Top in the first row and Margin.Bottom in the last row. With this class, you simply change the newly introduced ChildMargin property and be done - you will see the effect of the changes immediately, live in the WPF designer and at runtime.

Here is a screenshot of a simple form done with the default System.Windows.Controls.Grid class - without setting any special margins. You can see how narrow the space between the elements is and that it does not look very appealing.

Default Grid form example

And here is the same form done with the GridLayout. Note that only the class of the Grid has been changed - the child elements are exactly the same.

GridLayout form example

The best of all is that this has been done in very few lines of code. It just took two steps: The first was to introduce a new property in a class that derives from System.Windows.Controls.Grid that would define the margin that the cild elements of the new Grid would use. The second set was overriding

protected void MeasureOverride(Size)
that has been introduced in FrameworkElement. The overwritten version of MeasureOverride enumerates all children and changes their Margin accordingly. After that, the base version of MeasureOverride is called. This makes sure that, before each arrangement, the margins are updated correctly.

Here is the complete source-code of the GridLayout:


using System.Windows;
using System.Windows.Controls;

namespace GridLayoutTest
{
    // The GridLayout is a special Panel that can be used exactly like the Grid Panel, except that it
    // defines a new property ChildMargin. ChildMargin's left, top, right and bottom margins will be applied
    // to all children in a way that the children will have a vertical space of ChildMargin.Top+ChildMargin.Bottom
    // and a horizontal space of ChildMargin.Left+ChildMargin.Right between them.
    // However, there is no margin for the borders of the internal widget, so that the GridLayout itself can be
    // aligned to another element without a margin.
    // It's best to have a look at TestWindow, which effectively tests all possible alignments of children.

    public class GridLayout : Grid
    {
        public static readonly DependencyProperty ChildMarginProperty = DependencyProperty.Register(
            "ChildMargin",
            typeof(Thickness),
            typeof(GridLayout),
            new FrameworkPropertyMetadata(new Thickness (5))
            {
                AffectsArrange = true,
                AffectsMeasure = true
            });
        // The child margin defines a margin that will be automatically applied to all children of this Grid.
        // However, the children at the edges will have the respective margins remove. E.g. the leftmost children will have
        // a Margin.Left of 0 and the children in the first row will have a Margin.Top of 0.
        // The margins that are not set to 0 are set to half the ChildMargin's value, since it's neighbour will also apply it,
        // effectively doubling it.

        public Thickness ChildMargin
        {
            get { return (Thickness)GetValue(ChildMarginProperty); }
            set 
            {
                SetValue(ChildMarginProperty, value);
                UpdateChildMargins();
            }
        }

        // UpdateChildMargin first finds out what's the rightmost column and bottom row and then applies
        // the correct margins to all children.

        public void UpdateChildMargins()
        {
            int maxColumn = 0;
            int maxRow = 0;
            foreach (UIElement element in InternalChildren)
            {
                int row = GetRow(element);
                int column = GetColumn(element);
                if (row > maxRow)
                    maxRow = row;
                if (column > maxColumn)
                    maxColumn = column;
            }
            foreach (UIElement element in InternalChildren)
            {
                FrameworkElement fe = element as FrameworkElement;
                if (null != fe)
                {
                    int row = GetRow(fe);
                    int column = GetColumn(fe);
                    double factorLeft   = 0.5;
                    double factorTop    = 0.5;
                    double factorRight  = 0.5;
                    double factorBottom = 0.5;
                    // Top row - no top margin
                    if (row == 0)
                        factorTop = 0;
                    // Bottom row - no bottom margin
                    if (row == maxRow)
                        factorBottom = 0;
                    // Leftmost column = no left margin
                    if (column == 0)
                        factorLeft = 0;
                    // Rightmost column - no right margin
                    if (column == maxColumn)
                        factorRight = 0;
                    fe.Margin = new Thickness (ChildMargin.Left   * factorLeft,
                                               ChildMargin.Top    * factorTop,
                                               ChildMargin.Right  * factorRight,
                                               ChildMargin.Bottom * factorBottom);
                }
            }
        }

        // We change all children's margins in MeasureOverride, since this is called right before
        // the layouting takes place. I was first skeptical to do this here, because I thought changing
        // the margin will trigger a LayoutUpdate, which in turn would lead to an endless recursion,
        // but apparantly WPF takes care of this.

        protected override Size MeasureOverride(Size availableSize)
        {
            UpdateChildMargins();
            return base.MeasureOverride(availableSize);
        }


    }
}

You can download a complete project with an exhaustive test scenario here:

GridLayout test window

Download

Edit: I forgot to take the ColumnSpan and RowSpan into account in the first version. This lead to margins being too large when an element with a Column- or RowSpan was spanning to the rightmost or bottommost row or column. This has been fixed in version 1.1. Download link has been updated.

Wednesday, May 18, 2011

Using .NET and WPF in Win32 legacy applications, Part 1: The basics

Introduction

There are applications that are just impossible to port to any new technology, because of sheer size. Unfortunately, most of these applications are very important to their creators, such as commercial applications that have been developed for decades. Those applications often matured over the time and are satisfying a broad range of users. Rewriting these in a new programming language or a new framework, while being economical, would be impossible.

That's why interoperation and downwards-compatibility is something every new platform should provide. .NET, with it's new Windows Presentation Foundation (WPF) is one of these platforms. You can use .NET in the (from Microsoft's point of view) "legacy" C++ programming language through C++/CLR. And you can use WPF controls and windows in the now deprecated WinForms classes using the "interop" class System.Windows.Interop.HwndSource. Fortunately, since WinForms is built on raw Win32 API under the hood, this HwndSource class is suitable to be used to integrate WPF with raw Win32 applications as well. And it's not that hard at all.

For the impatient among us, you can directly skip to the download and look at the source code. It's only a few dozen lines of code.

Getting started

To get started, we will create a new, empty C++/CLR project. We need C++/CLR, since, obviously, we need to access .NET from either C or C++ source code. I will assume that the "legacy" application you want to use WPF in is a C++ project, since C projects can easily be ported or integrated with C++ code.

Step 1: Creating a new C++/CLR project

In Microsoft Visual C++ 2010 Express, you do that by choosing File -> New -> Project from the menu. Then you select Visual C++ > CLR > CLR Empty Project as the template. I picked win32wpfinterop as the project name, but you can use any name you want. When you hit OK, you will have a new, empty project.

Step 2: Building the Win32 window skeleton

Since C++/CLR is a superset of the "normal" C++ that you write in Visual C++, you can use the Win32 API just as you please. The window example skeleton does not differ from normal C++ at all. Add a new C++ File to the Source Files folder (filter) and add your Win32 window code. Here's how my code looks:

#include <Windows.h>

// Constants
namespace {
   TCHAR * windowClassName = TEXT("win32host");
   TCHAR * windowTitle     = TEXT("Win32 Host (Win32 WPF Interop)");
   int          windowWidth     = 200;
   int          windowHeight    = 100;
}

// Window message procedure
LRESULT CALLBACK WindowProc(
  HWND hwnd,
  UINT uMsg,
  WPARAM wParam,
  LPARAM lParam)
{
   switch (uMsg) {
   case WM_DESTROY:
      ::PostQuitMessage (0);
      return 0;
      break;
   default:
      return ::DefWindowProc (hwnd, uMsg, wParam, lParam);
   }
}

// Main program entry  point
[System::STAThread] // This is IMPORTANT, but it's for in C++/CLR  only
int CALLBACK WinMain(
   HINSTANCE hInstance,
   HINSTANCE hPrevInstance,
   LPSTR lpCmdLine,
   int nCmdShow)
{
   // Register our Window class
   ::WNDCLASS wndclass;
   wndclass.style = CS_VREDRAW | CS_HREDRAW;
   wndclass.lpfnWndProc = &WindowProc;
   wndclass.cbClsExtra = 0;
   wndclass.cbWndExtra = 0;
   wndclass.hInstance = hInstance;
   wndclass.hIcon = NULL;
   wndclass.hCursor = NULL;
   wndclass.hbrBackground = reinterpret_cast <HBRUSHgt; (COLOR_BTNFACE + 1);
   wndclass.lpszMenuName = NULL;
   wndclass.lpszClassName = windowClassName;
   ::RegisterClass(&wndclass);

   // Create our main, raw win32 API window
   // We create the window invisible (meaning that we do not provide WS_VISIBLE as the window style parameter), because making it visible and then
   // adding a HwndSource will make it flicker.
   HWND mainWindow = ::CreateWindow(
      windowClassName,
      windowTitle,
      0,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      windowWidth,
      windowHeight,
      NULL,
      NULL,
      hInstance,
      0);

   // Now that setting up the HwndSource is finished, we can finally make our window visible
   ::ShowWindow (mainWindow, SW_SHOW);

   // Start message processing
   ::MSG message;
   while (::GetMessageA(&message, 0, 0, 0)) {
      switch (message.message) {
      case WM_QUIT:
         break;
      default:
         ::TranslateMessage(& message);
         ::DispatchMessage(& message);
         break;
      }
   }
   return 0;
}

Download here

Yeah I know, it's a bit length ;-) but that's just how Win32 code is. The good news is that adding WPF components is much less code than this skeleton. Here is how your window should look like:

Empty Win32 Window

You need to add the User32.lib to your references, since the functions we used are defined in the Windows' User32 library. You need to right-click on your project in the Solution Explorer and choose Properties. Then navigate to Configuration Properties > Linker > Input and add User32.lib as an Additional Dependency.

Step 3: Create a HwndSource

Before we will be going to use WPF classes, we need to add the required WPF Assemblies to our project references. Right-click your project in the Solution Explorer again, but this time choose References. Now press Add New Reference and get a cup of coffee, while Visual Studio loads every registered .NET assembly. (This has become much faster in Visual Studio 2010, but it is still unbearably slow.) We will need the following assemblies to our project: System (for String), WindowBase and PresentationCore (for HwndSource) and PresentationFramework (for Label).

As the simplest example, we will be adding Label (type System.Windows.Controls.Label) to the window in this tutorial. But we can not just add a Label object to the Window -- the Label class has no members that would take a HWND as the parent class or anything like that. Instead, we need to create an intermediate object that builds the very bridge between Win32's HWND and WPF's System.Windows.UIElement. That intermediate object is of the aforementioned type System.Windows.Interop.HwndSource. Creating a HwndSource-object is very similar to creating a new win32 control - The HwndSource constructor basically takes the same parameters as WinAPI's RegisterClass () and CreateWindow() do. We create a HwndSource using this call:

System::Windows::Interop::HwndSource ^ hwndSource = gcnew System::Windows::Interop::HwndSource (
      CS_VREDRAW | CS_HREDRAW, // window class styles
      WS_CHILD,                // window flags
      0,                       // extended windows styles
      0,                       // x position (will be overridden later)
      0,                       // y position (will be overridden later)
      "WPF Interop",           // window title (not visible)
      static_cast <System::IntPtr> (mainWindow)); // parent window

HwndSource is, at the same time, a pure HWND-style window and a WPF UIElement. This means it can be hosted by another HWND (because we passed the WS_CHILD flag), but can host a WPF UIElement itself. And since being able to host one element in WPF means that you can host any number of elements (e.g. by using a Grid), you have the ultimate freedom to embed complex controls written in .NET and WPF in your Win32 application.

Step 4: Finally, add the Label

It's a bit tricky to get hold of the HWND window handle of HwndSource, because of .NET and C++ type differences. The HWND is available as a System.IntPtr. You need to call ToInt32 and reinterpret_cast it to a HWND like so:

HWND hwndSourceHandle = reinterpret_cast <HWND> (hwndSource->Handle.ToInt32 ());

Now we can call any Win32 API functions on that HWND, such as SetWindowPos:

::SetWindowPos (
      hwndSourceHandle,
      NULL, // ignored
      10,   // x position
      10,   // y position
      180,  // width
      80,   // height
      SWP_NOZORDER | SWP_SHOWWINDOW);

The HwndSource now exists, but that alone is not much of a gain. It's not even visible. You need to create some visible WPF control and add that to the HwndSource. Adding to the HwndSource means setting the control as the HwndSource's RootVisual. Here's how you can do this:

System::Windows::Controls::Label ^ label = gcnew System::Windows::Controls::Label ();
label->Content = gcnew System::String ("WPF Label -- it works!");
label->Background = System::Windows::Media::Brushes::White;

hwndSource->RootVisual = label;

When you insert this code between the call to ::CreateWindow() and ::ShowWindow(), you will experience your first moment of success and a window like this should be visible:

Win32 Window with WPF Label

Controls that don't required keyboard focus work very good. Controls with keyboard focus work good, too, as long as there are no other controls in the host window that may steal the focus from WPF. The next part will be about making keyboard handling and focusing work correctly, so stay tuned.
(Don't expect it before June or July 2011, though)

There's a complete example project for Visual C++ 2010 (build with VC++ 2010 Express) with commented source code for download.

Download

And besides: You can build a window's complete content in a C# class library e.g. as a UserControl, add that class library's assembly as a Reference in your C++/CLR's project and go ahead and use it in this interop framework we just built. This basically means that you can embed C# windows and controls in your legacy C++ application.

Friday, April 1, 2011

Avoiding Anti-Aliasing when drawing Rects, Lines in DrawingVisual's DrawingContext

When building my own high-speed grid control recently, I came across the problem that, when drawing the grid lines, they were anti-aliased and looked very ugly. I searched the web and came up with nothing for phrases like "anti aliasing drawingvisual" or "blurry lines drawingvisual" or even "crisp lines drawingvisual". None of them returned any result, until I came across an answer on StackOverflow (which I currently can't find again).

The solution is very easy, while not even remotely logical to anyone not knowing the deep internals of DrawingVisual. First, here is what you usually would try to draw lines from position (10, 10) to position (200, 10):

drawingContext.DrawLine(new Pen (Brushes.Black, 1), new Point(10, 10), new Point(200, 10));

The result would like something like this:

Non-antialiased line

As you can see, the line is not really black. And it is not one pixel wide. That's because it is rendered "blurry".

The obvious, totally intuitive way (oh, did you notice the irony?) to avoid this, you have to do this:

drawingContext.DrawLine(new Pen (Brushes.Black, 1), new Point(10.5, 10.5), new Point(200.5, 10.5));

And here is our desired result:

aliased line

Yes, you have to add 0.5 to your fraction-less position. And you will get pixel-perfect lines. This works for DrawRect, too.

Here's a full example with some grid lines:

class DrawElement : FrameworkElement
    {
        protected override void OnRender(DrawingContext drawingContext)
        {
            double x = 10.1;
            Pen pen = new Pen(Brushes.Black, 1);
            while (x < ActualWidth)
            {
                double actualX = Math.Ceiling(x) + 0.5;
                drawingContext.DrawLine(
                    pen,
                    new Point(actualX, 0),
                    new Point(actualX, ActualHeight));
                x += 10.1;
            }

            double y = 10.1;
            while (y < ActualHeight)
            {
                double actualY = Math.Ceiling(y) + 0.5;
                drawingContext.DrawLine(
                    pen,
                    new Point(0, actualY),
                    new Point(ActualWidth, actualY));
                y += 10.1;
            }
            base.OnRender(drawingContext);
        }
    }

And here's the result: