Direct2D and WinForms: It Just Works

About a month ago I ported the Curves adjustment UI to use Direct2D for the transfer map (the interactive spline/grid). This meant that a rectangular portion of the form was carved out for Direct2D. If you’ve used WPF interop then you’ll be familiar with “airspace limitations”, and I was curious as to whether it would be possible to put a WinForms button on top of an area that is being rendered to with Direct2D. In other words, if you use Direct2D to render to an area of a Form, does it completely take over that rectangular area?

image 

Now, you can always take a guess, “Well of course you could/couldn’t do that because of explanation involving logical deduction or other example setting precedent.” For engineering purposes, however, something like this must be shown to work before taking a dependency on it.

And what do you know, it does work:

image

This screenshot shows a Form that contains a single control of type “D2DThingy.” That control then has 5 children controls of various types, and they are all stock WinForms controls. Clearly, they are able to coexist peacefully and without artifacts like clipping or flickering. Like with any WinForms UI there is still a lot of work to make sure that the background of the Button matches up with what’s behind it, etc. but that is a known problem with known solutions.

This is of special importance to me because I want to write a new toolbar UI for Paint.NET v4.0. However, I absolutely do not want to write my own ComboBox or TextBox controls. I could spend a full 12 months on a globalized TextBox that can work with all languages, input types, etc. Thankfully I won’t have to.

Advertisement

7 thoughts on “Direct2D and WinForms: It Just Works

    • Bubo says:

      Well microsoft released the SDK for it, and Paint.NET 4 is supposed to a new ui. My guess is it could be ribbon based,

  1. Matt Warren says:

    How do you make sure that the background of a button matches up with what’s behind it? I use a similar technique to your to put buttons/sliders on-top of a live video stream that is displayed using Direct2D. But you can always see the shadow round buttons that looks a bit wierd.

  2. Rick Brewster says:

    Matt, generally this is done by deriving a new class from any control you want to support a transparent background. For example: TransparentButton, TransparentCheckBox, etc.

    In the constructor call SetStyle twice, once to set AllowsTransparentBackground to true and then again to set Opaque to false. Then set the BackColor property to Color.Transparent.

    What this does is ensure that in the control’s OnPaintBackground it will actually call its parent control’s painting methods. If you’re using something like DirectX then you will still have some trouble because that stuff doesn’t go through OnPaint (aka, WM_PAINT). So the trick there is to make sure that the parent control of that button has a “reasonable” solid color that will work good *enough* with the actual content you’re putting there. Or you could really go far out and make sure that the OnPaint method can extract that tiny sliver of pixels from the active video frame. But that might be way too expensive.

        internal sealed class TransparentCheckBox
            : CheckBox
        {
            public TransparentCheckBox()
            {
                SetStyle(ControlStyles.SupportsTransparentBackColor, true);
                SetStyle(ControlStyles.Opaque, false);
                BackColor = Color.Transparent;
            }
        }

    Keep in mind that this is not a general purpose, perfect solution: User32/WinForms do not actually support true rendering composition, they only have a few tricks that work “well enough” for “many” uses.

    • Matt Warren says:

      Rick, thanks for the info, I’ll try it out, although I’ll struggle to choose a “reasonable” solid colour for the background and analysing the live video will be way too expensive as you say.

      Thanks for the help

  3. GoD says:

    What interop DLLs do you use to use Direct2D with .Net?
    In my tests, it was really slow to use it in .Net.
    With 1920×1080 and some rectangles and some texts,
    I got only a frame rate of about 10 fps. That’s to slow
    for zooming and scrolling. So how did you solve this problem?

  4. Rick Brewster says:

    It should be clear from this post and my previous posts that I have written my own interop layer. I never said I was solving the same issue you’re having; I have no idea what your code looks like.

Comments are closed.