Pages

Wednesday, 27 April 2011

How to create a non-rectangular image in Silverlight, WPF and WinForms

Introduction
In Windows Forms, it’s quite hard to create a display like this one without doing a lot of work  :

 ImageBrush1  
And just for avoidance of doubt, this isn’t a rectangular picture box or image that contains an oval shape and a transparent background. The element here isn’t contained in a rectangle, it’s genuinely oval so it neatly avoids those problems you can get with overlapping controls when using a Windows Forms PictureBox. 

Just to test that claim, here’s the image with a bordered TextBlock set next to it:

ImageBrush2

As you can see, there’s no overlap issue here.   Although it can be tricky to create such a control in Windows Forms, creating an element like this in WPF and in Silverlight is so simple you’d hardly believe it.

WPF and Silverlight Version
Using XAML, you can create the first effect with the following markup:





Let’s look briefly at the XAML. 

Firstly, an ellipse is created to hold the image.  The Ellipse object has a Stroke property that represents the color to be used for the outside edge of the ellipse.  (Notice that I carefully avoided using the word ‘Border’ there, for good reason.  WPF and Silverlight both offer a Border element, but we don’t need to use that here.)

It also has a StrokeThickness property, whose purpose is obvious, and I’ve set this to an arbitrary thickness of 7.  This is what creates the frame effect.

The next property to look at is the Fill property.  In cases where the value of a property is complex (in this particular example, where the fill isn’t simply a solid color), you need to use this kind of property-element syntax.  Essentially, all you do is create opening and closing tags for the property (in this case Ellipse.Fill) and then insert the required settings or additional sub-elements between the tags. 

In this example, that sub-element is an ImageBrush object, and that’s really the key that makes this work.   The ImageBrush is assigned an ImageSource, rather than a solid color or gradient color that you’d normally expect to see used by a brush.  And the brush can use this image to paint any area – in this case the fill area of the ellipse.

Of course, if you don’t want the frame effect, you can just remove the Stroke and StrokeThickness properties:





ImageBrush3

And, if a plain old oval shape isn’t what you need then you can apply Transforms to rotate or skew the shape.  I won’t cover those here, but may come back to them in a later blog.

Windows Forms Version
So, that’s fine if you’re building a WPF or Silverlight application, but what if you need this in Windows Forms? Well, one of the easiest ways is to use interop, which will allow you to insert this ellipse into a form by hosting it in a Windows Forms ElementHost control.

Here are the steps you need to follow:

In a Windows Forms project, use the Add—>New Item menu item and add a User Control(WPF) item from the WPF templates.  In my sample project, I named this OvalImage. 

Next, if you don’t already have the image you want to use, add one to the project in the usual way:  Add—>Existing Item.

Change the DesignHeight and DesignWidth properties of the user control as necessary.  I’ve used:

d:DesignHeight="150" d:DesignWidth="130">

Create the composite element by adding a Canvas, an Ellipse,and then using an ImageBrush to fill the ellipse:







Change any of the size or margin settings as needed for your particular image.

Then, switch to the Windows Form in Design view and drag an ElementHost control from the WPF Interoperability tab of the Toolbox.  if you can’t see this tab, then you probably still have the WPF User Control selected, in which case you’ll only be able to see WPF elements in the Toolbox.

Click on the smart tag of this control and select the user control (OvalImage in my example) as the Hosted Content.  The image should appear inside the ElementHost control, but it may be clipped.  Don’t worry if it is:

ImageBrush5

Build and Run the project.  You should see a result something like this (i.e. the clipping has disappeared:

ImageBrush6

As an experiment, I’ll add a label to the form and position it so that it sits on top of the ElementHost.

ImageBrush7

The trick here is to right-click on the label and select the bring To Front menu item.  When you run the project, you’ll see:

ImageBrush8

A neat finish, with the rectangular label and the non-rectangular image seamlessly fitting together.

Summary
If you’re not able to use WPF or Silverlight as the application type, you can still take advantage of some of their graphical tools in a Windows Forms application, thanks to the easy use of interop.

Posted Apr 20 2011, 04:45 PM by Ged Mead Filed under: XAML, WPF, Interop, .NET, VB.NET, Visual Basic.NET, Visual Basic, UserControl, Image

View the original article here

0 comments:

Post a Comment

 
Powered by Blogger