Click here to Skip to main content
15,867,686 members
Articles / Silverlight

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

Rate me:
Please Sign up or sign in to vote.
4.93/5 (16 votes)
17 May 2009CPOL2 min read 65.2K   14   14
This technical blog posts shows how to add a new property ClipToBounds to clip your UI Elements.

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:

XML
<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:

XML
<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:

XML
<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:

C#
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, its 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.

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)


Written By
Architect Scott Logic
United Kingdom United Kingdom
I am CTO at ShinobiControls, a team of iOS developers who are carefully crafting iOS charts, grids and controls for making your applications awesome.

I am a Technical Architect for Visiblox which have developed the world's fastest WPF / Silverlight and WP7 charts.

I am also a Technical Evangelist at Scott Logic, a provider of bespoke financial software and consultancy for the retail and investment banking, stockbroking, asset management and hedge fund communities.

Visit my blog - Colin Eberhardt's Adventures in .NET.

Follow me on Twitter - @ColinEberhardt

-

Comments and Discussions

 
Generalnice Pin
devYang757-Jun-15 22:43
devYang757-Jun-15 22:43 
GeneralMy vote of 5 Pin
Kashif_Imran21-Aug-13 9:22
Kashif_Imran21-Aug-13 9:22 
GeneralWithout code behind Pin
Sorin Dolha10-May-13 4:01
Sorin Dolha10-May-13 4:01 
GeneralMy vote of 5 Pin
hari111r27-Jan-13 4:55
hari111r27-Jan-13 4:55 
GeneralMy vote of 5 Pin
Martin Lottering27-May-12 5:56
Martin Lottering27-May-12 5:56 
GeneralMy vote of 5 Pin
RonSau20-Mar-12 9:57
RonSau20-Mar-12 9:57 
QuestionAwesome! Pin
Lynx468515-Dec-11 4:01
Lynx468515-Dec-11 4:01 
GeneralExactly what I needed Pin
Marc Schluper29-Nov-10 6:23
Marc Schluper29-Nov-10 6:23 
QuestionHow does one set this in code Pin
KenJohnson29-Jul-10 23:18
KenJohnson29-Jul-10 23:18 
QuestionHow do i clip a canvas against polygon. Pin
mayurparmar0216-Mar-10 20:27
mayurparmar0216-Mar-10 20:27 
AnswerRe: How do i clip a canvas against polygon. Pin
Colin Eberhardt17-Mar-10 4:44
Colin Eberhardt17-Mar-10 4:44 
GeneralSee it in use! Pin
Helen Warn18-Jul-09 15:21
Helen Warn18-Jul-09 15:21 
GeneralI works ! Pin
Benjamin Mayrargue10-Jun-09 9:50
Benjamin Mayrargue10-Jun-09 9:50 
Generalnice ! Pin
Benjamin Mayrargue10-Jun-09 9:42
Benjamin Mayrargue10-Jun-09 9:42 

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

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