UPDATES:
> You can see another simple example here.
> Why stop at simple geometry masks? Howabout images with holes?![]()
WPF’s Border element allows you to specify a different radius for each corner. Unfortunately it doesn’t clip content to fit inside the boundary (example here and below):
While there are other solutions, this one is my favorite so far:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="Black"> <!-- Rounded yellow border --> <Border BorderThickness="3" BorderBrush="Yellow" CornerRadius="10" Padding="2" HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid> <!-- Rounded mask (stretches to fill Grid) --> <Border Name="mask" Background="White" CornerRadius="7"/> <!-- Main content container --> <StackPanel> <!-- Use a VisualBrush of 'mask' as the opacity mask --> <StackPanel.OpacityMask> <VisualBrush Visual="{Binding ElementName=mask}"/> </StackPanel.OpacityMask> <!-- Any content --> <Image Source="http://chriscavanagh.files.wordpress.com/2006/12/chriss-blog-banner.jpg"/> <Rectangle Height="50" Fill="Red"/> <Rectangle Height="50" Fill="White"/> <Rectangle Height="50" Fill="Blue"/> </StackPanel> </Grid> </Border> </Page>
All it does is include a ‘mask’ Border element as a sibling of the content you want to clip. In the content it uses a VisualBrush bound to that mask. The mask will be automatically sized to your content, so it’s a nice "set and forget" solution
The downside is it won’t work in Silverlight because ElementName binding isn’t supported (yet). No doubt it’s possible to assign the VisualBrush in code-behind though! (let me know if you try it). (oops, neither is VisualBrush!)
Hope this helps (and please let me know of any better / cleaner solutions).
25 responses so far ↓
Dew Drop - October 4, 2008 | Alvin Ashcraft's Morning Dew // October 4, 2008 at 8:40 am |
[...] WPF – Easy Rounded Corners for Anything (Chris Cavanagh) [...]
Daniel Kemper // October 28, 2008 at 8:49 pm |
Hi Chris,
Can you try something like this, at your leisure, with a file loaded as a resource, and let me know if you get strange results when resizing the window? The rounded corners seem to collapse. Here, I really just plugged in your XAML to the stock WPF project window.
Daniel Kemper // October 28, 2008 at 8:51 pm |
… dont’ think the XAML pasted into the comment area made it to the published post. I’ll post a link to the full solution ….
Dan
Daniel Kemper // October 28, 2008 at 8:53 pm |
Here you go!
http://dankemper.net/BorderMaskEx1.zip
Thanks,
Dan
Chris Cavanagh // October 28, 2008 at 10:22 pm |
Daniel – The problem is caused by the image being stretched bigger than the available area. Because it’s contained in a StackPanel (with default vertical orientation) it’ll allow the content to grow as tall as it wants. To confirm this try changing the StackPanel to a Grid…
Are you wanting the brushed aluminum image to act as a background? If so, you might prefer to assign it as an ImageBrush to the StackPanel’s Background property (or do your own LinearGradientBrush with an aluminum OpacityMask…).
Hope this helps!
rem // November 16, 2008 at 2:08 am |
Helpfull blog…
Stewart Hyde // December 12, 2008 at 11:39 pm |
This is not exactly related to mask graphics issue here but I attempted to use this technique with WebBrowser control that is overlapping objects that are below the web control.
The web control is inside ScrollerViewe inside one of expanders. This is a set Grid and with bottom grid on top this so it at bottom of screen.
Chris Cavanagh // December 13, 2008 at 9:16 am |
Stewart – I might be misunderstanding your comment, but WebBrowser isn’t a “proper” WPF control. It’s just a wrapper around the IE ActiveX control and suffers from several restrictions associated with ActiveX. The main problem is it can only render directly to the screen rather than arbitrary surfaces, so WPF can only control its size and position (and can’t do nice things like clip its corners or apply transformations).
Does that help?
Chris Cavanagh // December 13, 2008 at 9:20 am |
Stewart – With some hacking, it is possible to get WPF to render and allow interaction with WebBrowser content, but it’s not pretty…
Take a look here: http://chriscavanagh.wordpress.com/2008/09/04/youcube/
James Foster // December 29, 2008 at 10:59 am |
Why not just add a padding attribute to the outer border control? This seems overly complex. Am I missing something here???
Chris Cavanagh // December 29, 2008 at 11:20 am |
James – The main goal of this is to allow any content to be clipped to a rounded border (or any shape actually), without having to know its size. While it’s easy to define a clip rectangle with rounded corners, you need to know the exact size… Padding only helps if your content doesn’t need to go right up against the border.
I’ve probably not explained it very well… Try the example above in Kaxaml or IE and resize the window. Then try doing the same thing using other methods. Definitely let me know if you find a simpler / better solution though; I certainly don’t claim to be an expert!
Thanks for the feedback!
Dean // February 9, 2009 at 4:25 am |
Very nice tutorial!
Sarkastik // March 16, 2009 at 5:35 pm |
One issue with this, I have an image with alpha transparency and don’t want the white background. Yet still need to have the image clipped.
Chris Cavanagh // March 16, 2009 at 8:56 pm |
Sarkastik – Not sure if this will work for you, but you could try applying another opacity mask to the corner mask itself… Something like this:
http://www.chriscavanagh.com/chris/TransparencyClipTest/TransparentClipTest.xaml
David // April 3, 2009 at 2:41 am |
Chris,
When I set this in a stackpanel as shown above I get no other content rendered inside the border.
David // April 3, 2009 at 2:55 am |
Ref My post above, If I place the opacity mask on ANY placeholder then the rest of the content that it contains is not shown.
Chris Cavanagh // April 3, 2009 at 7:16 am |
H David – Please send me some XAML that shows the problem. Some elements resize in interesting ways that can affect this (but I’ve not found any “impossible” cases… yet
)
David // April 6, 2009 at 12:55 am |
…..rest of content
David // April 6, 2009 at 12:57 am |
Chris, Tried to post the Xaml here but it cuts out the markup. Can I email you the xaml I am using?
Chris Cavanagh // April 6, 2009 at 1:19 am |
David – Just send to blog at chriscavanagh dot com
(or maybe the ’send email’ option on my Contact page… I *think* it lets you paste code…)
David // April 6, 2009 at 6:52 am |
Nope .. it says not to post code on the contact form
Will email @ above address
David // May 21, 2009 at 12:07 pm |
Chris,
I’ve noticed that if you place any hardware accelerated effects onto items contained within the masked element that the masking breaks down. Don’t know if you’ve had this experience or know a work around but I thought it was worth mentioning.
Chris Cavanagh // May 21, 2009 at 12:18 pm |
David – Can you send an example?
I tried a simple test here: http://www.chriscavanagh.com/chris/ClipWithShadow.xaml (you’ll need to download & run in Kaxaml/Xamlpad; you’ll probably get a UIPermission exception if you just open in IE).
David // May 26, 2009 at 3:41 am |
Chris,
I figured it out, the item I was containing was a png image that had alot of transparency around the actual visible image. The overall image ran to the edge of the parent container with rounded corners. When the DropShadow is added the corners break. I placed a large margin around the image and the corners were sorted out.
Chris Cavanagh // May 26, 2009 at 6:48 am |
David – Great! Could you send me a couple screenshots comparing the two? Thanks!