Click here to Skip to main content
Licence CPOL
First Posted 16 May 2009
Views 22,114
Downloads 0
Bookmarked 10 times

Silverlight ClipToBounds - Can I Clip It?, Yes You Can!

By Colin Eberhardt | 17 May 2009 | Technical Blog
This technical blog posts shows how to add a new property ClipToBounds to clip your UI Elements.

1

2

3
1 vote, 10.0%
4
9 votes, 90.0%
5
4.89/5 - 10 votes
μ 4.89, σa 0.99 [?]
A Technical Blog article. View original blog here.[]

With Silverlight, Panels do not clip their contents by default. See the following example:

noclip

Where we have a Grid containing another Grid which itself contains an ellipse, and a Canvas which contains an ellipse:

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
 
    <Grid Grid.Column="0" Background="Blue" Margin="20">                        
        <Grid Background="Yellow" Margin="20,40,-20,20">
            <Ellipse Fill="LightGreen" Width="80" 
		Height="80" Margin="-40, -40, 0, 0"/>
        </Grid>
    </Grid>
 
    <Canvas Grid.Column="1"  Background="Aqua" Margin="20" >
        <Ellipse Fill="Red" Canvas.Top="-10" 
		Canvas.Left="-10" Width="130" Height="130"/>
    </Canvas>
</Grid>

Often this is not the desired effect (although it is actually quite a useful feature of Canvas; You can simply add a Canvas to your visual tree without explicitly or implicitly setting its Size and use it as a mechanism for absolute positioning its children).

Fortunately Silverlight provides a Clip property on UIElement, allowing you to provide the clipping geometry for the element:

<Grid Width="200" Height="100">       
    <Grid.Clip>
        <RectangleGeometry Rect="0, 0, 200, 100"/>
    </Grid.Clip>
</Grid>

The above example creates a clipping geometry which matches the rectangular geometry of the Grid itself. Clearly more funky clipping geometries can be created, allowing for really cool effects, however most of the time I simply want my Panel clipped so that its children cannot escape!

The above example has a few problems. Firstly, it is a bit long-winded having to explicitly create the geometry each time I want to clip; Secondly, if my Grid’s size is calculated from its parent’s layout, how can I define the clip geometry in my XAML? Finally, if my Grid’s geometry changes, its clipped geometry does not change.

In order to solve this problem, I created a simple little attached behaviour, which allows you to define the clipping using the attached property Clip.ToBounds as illustrated below:

<UserControl x:Class="SilverlightClipToBounds.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:util="clr-namespace:Util" Width="300" Height="200">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
 
        <Grid Grid.Column="0" Background="Blue" Margin="20" util:Clip.ToBounds="true">
            <Grid Background="Yellow" Margin="20,40,-20,20" util:Clip.ToBounds="true">
                <Ellipse Fill="LightGreen" Width="80" 
		Height="80" Margin="-40, -40, 0, 0"/>
            </Grid>
        </Grid>
 
        <Canvas Grid.Column="1"  Background="Aqua" Margin="20" util:Clip.ToBounds="true">
            <Ellipse Fill="Red" Canvas.Top="-10" 
		Canvas.Left="-10" Width="130" Height="130"/>
        </Canvas>
    </Grid>
</UserControl>

The result can be seen below:

crop

And here is the code for the attached behaviour itself:

public class Clip
{
    public static bool GetToBounds(DependencyObject depObj)
    {
        return (bool)depObj.GetValue(ToBoundsProperty);
    }
 
    public static void SetToBounds(DependencyObject depObj, bool clipToBounds)
    {
        depObj.SetValue(ToBoundsProperty, clipToBounds);
    }
 
    /// <summary>
    /// Identifies the ToBounds Dependency Property.
    /// <summary>
    public static readonly DependencyProperty ToBoundsProperty =
        DependencyProperty.RegisterAttached("ToBounds", typeof(bool),
        typeof(Clip), new PropertyMetadata(false, OnToBoundsPropertyChanged)); 
 
    private static void OnToBoundsPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement fe = d as FrameworkElement;
        if (fe != null)
        {
            ClipToBounds(fe);
 
            // whenever the element which this property is attached to is loaded
            // or re-sizes, we need to update its clipping geometry
            fe.Loaded += new RoutedEventHandler(fe_Loaded);
            fe.SizeChanged += new SizeChangedEventHandler(fe_SizeChanged); 
        }
    }
 
    /// <summary>
    /// Creates a rectangular clipping geometry which matches the geometry of the
    /// passed element
    /// </summary>
    private static void ClipToBounds(FrameworkElement fe)
    {
        if (GetToBounds(fe))
        {
            fe.Clip = new RectangleGeometry()
            {
                Rect = new Rect(0, 0, fe.ActualWidth, fe.ActualHeight)
            };
        }
        else
        {
            fe.Clip = null;
        }
    }
 
    static void fe_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        ClipToBounds(sender as FrameworkElement);
    }
 
    static void fe_Loaded(object sender, RoutedEventArgs e)
    {
        ClipToBounds(sender as FrameworkElement);
    }    
}

When the ToBounds property is associated with an element, ClipToBounds is invoked to create a rectangular clip geometry. We also add event handlers for Loaded, which is a very useful event which is fired when an element has been laid out and rendered, in other words it’s size will have been computed, and SizeChanged. In the event handlers for both, we simply update the clipping geometry.

This can be seen in action here, where clicking on the Grids or Canvas increases their size, with the clipping geometry growing accordingly:

[CodeProject does not support Silverlight applets, see it in action on my blog]

You can download a demo project here: sliverlightcliptobounds.zip.

Can I Clip It?, Yes, You Can!

Regards, Colin E.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Colin Eberhardt

Architect
Scott Logic
United Kingdom United Kingdom

Member
Visit my blog - Colin Eberhardt's Adventures in WPF.
 
I am currently working as a Technical Architect at Scott Logic, a provider of bespoke financial software and consultancy for the investment banking, stockbroking, asset management and hedge fund communities.
-

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionAwesome! PinmemberLynx46855:01 15 Dec '11  
GeneralExactly what I needed PinmemberMarc Schluper7:23 29 Nov '10  
QuestionHow does one set this in code PinmemberKenJohnson0:18 30 Jul '10  
QuestionHow do i clip a canvas against polygon. Pinmembermayurparmar0221:27 16 Mar '10  
AnswerRe: How do i clip a canvas against polygon. PinassociateColin Eberhardt5:44 17 Mar '10  
GeneralSee it in use! PinmemberHelen Warn16:21 18 Jul '09  
GeneralI works ! PinmemberBenjamin Mayrargue10:50 10 Jun '09  
Generalnice ! PinmemberBenjamin Mayrargue10:42 10 Jun '09  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120209.1 | Last Updated 18 May 2009
Article Copyright 2009 by Colin Eberhardt
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid