UPDATES:
> You can see another simple example here.
> Why stop at simple geometry masks? Howabout images with holes? 🙂
> Why stop at WPF? Here’s a Silverlight 3 version!
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="https://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!). There’s now a Silverlight version here!
Hope this helps (and please let me know of any better / cleaner solutions).
[…] WPF – Easy Rounded Corners for Anything (Chris Cavanagh) […]
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.
… 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
Here you go!
http://dankemper.net/BorderMaskEx1.zip
Thanks,
Dan
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!
Helpfull blog…
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.
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?
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: https://chriscavanagh.wordpress.com/2008/09/04/youcube/ 🙂
Why not just add a padding attribute to the outer border control? This seems overly complex. Am I missing something here???
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!
Very nice tutorial!
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.
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
Chris,
When I set this in a stackpanel as shown above I get no other content rendered inside the border.
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.
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 🙂 )
…..rest of content
I am having trouble with this leaving me with just the boarder visible with the entire contents of my grid / stack panel masked out. Any idea what I may be doing wrong for this to be happening?
stoneweasel – Can you email a code snippet to blog at chriscavanagh.com? Will take a look 🙂
Chris, Tried to post the Xaml here but it cuts out the markup. Can I email you the xaml I am using?
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…)
Nope .. it says not to post code on the contact form 😦 Will email @ above address
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.
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).
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.
David – Great! Could you send me a couple screenshots comparing the two? Thanks!
Hey Chirs. Thank you for sharing this. I wrote a simple wrapper around your solution, to make a free form borders. Check it out: http://stackoverflow.com/questions/1356999/wpf-freeform-border-control/1358132#1358132
Anvaka – That’s great! 🙂 I could use something like this for some of my apps. Thanks!
Thanks,
However, I am using expression blend for silverlight 3 and I am getting a message that “VisualBrush does not exist”
Am I missing something?
Please let me know.
Thanks again.
[…] · Leave a Comment As you know Silverlight 3 doesn’t support VisualBrush, which can make things like this pretty […]
Mahesh – Unfortunately Silverlight 3 doesn’t support VisualBrush so this method doesn’t work. Your comment prompted me to try a Silverlight version:
https://chriscavanagh.wordpress.com/2009/09/24/silverlight-visualbrush-and-rounded-corners/
Let me know if this helps!
Any ideas how I could get a transparent background with this? Since the Border is used as an Opacity Mask, any tries to set transparency to it also sets transparency to the content.
Any ideas? 😦
PienaZipa – You should be able to do this with extra sibling elements to the mask; something like this:
http://www.chriscavanagh.com/chris/CornerClippingTransparency.xaml
(Try “download as” to get the xaml source). This example applies the OpacityMask to both siblings [of the mask], but you really only need to apply it to elements that need to be clipped (so for instance if a sibling had Margin=”20″ or something, it might not need clipping at all).
Hope tihs helps!
Thanks for replying. However, I tried your sample and, no matter how hard I try, it doesn’t work as desired (entirely transparent through to desktop – the window is semi-transparent).
I posted the relevant XAML for the ListBox at http://pastebin.com/m38a785c2 – could you please take a look at it? Thank you 🙂
PienaZupa – I’ll take a look at this. Please describe exactly the effect/behavior you’re hoping to achieve 🙂 (can’t figure out from what you’ve sent so far).
Thanks 🙂
Okay, first of all I have a window, which has the Aero-glass transparency effect – you can see the desktop. Then I have this semi-transparent listbox, for which I have created a custom style/controltemplate (it’s the code in the link I posted). This listbox, in turn, generates items which also have semi-transparent backgrounds.
In the end of the day a have a listbox with a bunch of items, but I can still see the desktop background through them (http://i48.tinypic.com/wa3td3.jpg),
and I want to make the stackpanel or scrollviewer (the one that contains the generated items, it’s in the code I put in the pastebin) have rounded corners 🙂 However, if I use the mask as it is, I lose the transparency.
Also for me setting an opacity for the listbox or scrollviewer or stackpanel isn’t going to work since it applies to children (including the generated text, as in the image) 😦
Hello.
This seems a nice, quick way to get the job done. Definitely appreciate the info as we’re all encountering this problem when we really shouldn’t. WPF is all about a new presentation platform geared toward robust visuals (apart from the other important gui-seperation from code aspects) so for it NOT to provide a more streamlined, native approach at natural container clipping for complex custom borders is .. I’ll say annoying.
Anyway good stuff. I may have missed it but I didn’t see any addition by anyone to address linking the mask corner radius to the main form border radius so I added this to your solution in my code and it seems to work pretty well.
Assuming the name of the outer form border is borderMainWindow, the following lets the mask corner radius be flexible and not have to be touched again if you change the outer radius settings:
Thanks again for the good idea to get around this annoying issue.
-Michael
Guess I needed to wrap the XAML oops. I’ll try again. Probably be another missing chunk sorry if so.
Just in case wrapping in a code tag still didn’t work and my example doesn’t show up, all I’m doing is binding the CornerRadius of the mask to ElementName borderMainWindow, Path CornerRadius.
Sorry to clutter up the comments with failed attempts at posting my sample. Obliterate and rewrite as you see fit.
Thanks again,
-Michael
Michael – Thanks for the feedback (sorry for the lousy comment editor :)). Good idea on binding the CornerRadius!
Freakin Sweet! Thanks so much man. I have been looking for an easier way to accomplish this for some time. This is a great idea. Keep up the good work. 🙂
[…] https://chriscavanagh.wordpress.com/2008/10/03/wpf-easy-rounded-corners-for-anything/ wpf This entry was posted on Jun 15th, 2010 at 3:44 PM and is filed under Programming, […]
Hi Chris !
This is a nice tutorial, thank you. But I have a problem when I try to use this.
I apply the OpacityMask to a Canvas. The corner are rounded, that’s good but… my window is white ! The mask don’t act as an OpacityMask but as a brush.
However, I can always use my controls… if I find them ! :p
Do you have experienced this type of problem in the past ?
Regards,
Michaël
Michaël – It sounds like your mask is defined after the content you’re masking… This technique relies on your content “covering” the mask shape (ie being declared after it in the XAML). Or it could be another issue entirely 🙂 Could you mail me some sample XAML? (blog at chriscavanagh.com)
Chris,
AS you ask me to do, I have send you a piece of code. 🙂
Michaël – Thanks for the example 🙂 The problem there is your mask is also the container of your content. The mask needs to be a “sibling” of your content (rather than a parent of it). Generally I find the best way is to use a Grid as the container/parent, then inside that have the mask (with no width or height specified so it fills the container) followed by the content. The content then has its OpacityMask pointing to the mask element (via the VisualBrush). Let me know if you need some more examples and I’ll fire you an email 🙂 (the blog comments section doesn’t like markup).
Hope this helps!
Oh yes, I’m so studip. On all the example that I have seen, I don’t have noticed that the border is not containing the element I want to apply the mask.
I don’t know why, but I was SURE that the border contained the element on which I want to apply the mask. What a stupid mistake !
Thank you for your help Chris. 🙂
Regards,
Michaël
If you replace the border with this
you will notice a small line and the left top between te yellow and the image which should not be there.
(my code was gone, 2nd attempt)
If you replace the first border settings with
BorderThickness=”20″
CornerRadius=”60″
Padding=”0″
and the 2nd border mask with
CornerRaduis=”50″
You will notice a small black line at the left,top position between the yellow and the image
i f you need to create rounded image, you can try this
The only problem is that you have to round to a certain background color, which creates only an illusion of rounded corners. You can’t place the rounded corners image on a non-white surface (in this particular example). If you do, you will end up with your image being rounded with white corners on some different background.
In my task I was to create an image from WPF object with rounded corners to place the image as an icon to notification area. This way I would get a dynamically generated notification area icon. This example doesn’t works in my particular case.
Max – Can you send an example?
Nice solution. It should be noted that in some cases you can just use the background of the border. This is true for your example of putting an image inside the border, you can just set the border’s background to an imagebrush.
I suspect this xaml will disappear but here is an example:
Yep it did 🙂
Here is is without the gt and lts
Border BorderThickNess=5 CornerRadius=10
Border.BackGround
ImageBrush ImageSource=”path to image here”
Close Border.BackGround
Close Border
Note that WebBrowser is not native WPF control (because WebBrowser is made by using winforms host control), so it can’t be stylized like this.
Bizunas – That’s correct, although a WPF WebBrowser like this – https://chriscavanagh.wordpress.com/2009/08/25/a-real-wpf-webbrowser/ – should work fine 🙂
Note also that Awesomium now comes with its own .NET Wrapper; the styling ought to work well with that too
Anyone has a solution/workaround for opacity mask not working correctly on 64 Bit machines (not always)?
For example:
If you put the XAML above in a Window, and compile your application as x64, then you will not see the text (or anything that is being masked).
It happens on Zoom and Rotate (a combination of them), for each scaling there are specific angles that the mask doesn’t render correctly.
Compiling my application as x86 is not an option.
I’ve tried other solutions for creating a round rectangle border like this, but Opacity Mask is the only one that gives the desired result, but still, other working solutions will be welcome.
Thanks
mmm, the XAML I’ve posted is not visible…
Just have the XAML of this blog changed so the Grid will have RenderTransform with Render Group that contains RotateTransform of 45 deg, and then ScaleTransform of ScaleX and ScaleY equals to 2.
Bug already reported by my here:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/25c05f8e-b8b8-4103-a5cf-2c51fc2d4b78
Sorry for the bad XAML on that example. That was after ripping all the XAMLs, DLLS, etc from the huge 40 Dlls project until I got a minimal project that simulates the problem (I only then discovered that the reason I couldn’t reproduce the problem on a clean solution was the fast that the new one was on x86… I didn’t know at that time that this problem is x64 related).
Saragani – That’s pretty strange. Is it possible to test in on non-NVidia machines? Seems they’ve had driver / WPF 64 issues in the past, so might be worth looking into:
http://connect.microsoft.com/VisualStudio/feedback/details/297127/broken-wpf-rendering-on-64bit-vista
How to clip window
pranav – See Cory Plotts’ comments here: http://social.msdn.microsoft.com/Forums/hu-HU/wpf/thread/91efcf9e-e887-405f-940d-0a57a697477c
The solution does not work if the horizontal- and verticalalignment is set to Strecth??
MM – It should work with pretty much anything. Could you send an example? (email to blogmm@chriscavanagh.com).
[…] We need a transparent border with rounded corners which clips the content. In the article WPF – Easy rounded corners for anything you can read how to achieve this. The result […]
Hi,
First of all, thanks for this solution. Been cracking my head on how to get rid of the ugly corners of my contents within a rounded control.
But I’ve run into a weird (to me) issue when I tried to incorporate this into my project. I’m using a Selector, in which I have several “pages” which are essentially UserControls which I display one by one progressively. Something like a Wizard. All the pages utilizes your OpacityMask method to achieve the rounded corner effects. But somehow only the first page displayed is able to show the contents of the rounded control. In the subsequent pages, it’s almost like the the “mask” border is in front of the contents, or simply the contents are not displayed. I checked my codes numerous times, but cannot figure out why, coz all the codes are almost identical except for the contents.
I’m hoping you might have some ideas as to how this can happen and how to resolve this… Would be so grateful for your help…
Ring – Could you email me a sample that demonstrates the problem? (xaml at chriscavanagh dot com).
Works in my case, much simpler
–Border BorderBrush=”Black” Width=”60″ Height=”60″ CornerRadius=”7″–
–Border.Background–
–ImageBrush ImageSource=”{Binding Path=Photo}” Stretch=”Fill” /–
–/Border.Background–
–/Border–
I use OpacityMask and VisualBrush for new project window Phone 8.1
But report: the member “OpacityMask” is not recognized or is not accessible
and the type “VisualBrush” was not found….
now, what can I import for my project to use OpacityMask and VisualBrush?
thanks!
I have problem same you
A totally different approach, if you have a solid color background on the Window/page is to just create a bitmap that is a rectangle, and in the bitmap have the rounded corner effect that you want. I know that is a lot of hassle for just one button, but if you reuse it over and over it is not bad.
What if the grid contain rows and columns inside it?
Uuuufffff! Brother it really helped me Thanks ❤