Can't get ClipToBounds to work... or why is my content being clipped

Jaime Rodriguez
On Windows Phone, Windows Presentation Foundation, Silverlight and Windows 7

Can't get ClipToBounds to work... or why is my content being clipped

  • Comments 2

I often get pinged with a "My < insert control or panel here> is clipping ... even though I have set ClipToBounds=false...  is this a bug?" ... 

It is not a bug; it is just that ( as of today, afaik) the clipping behavior in WPF is not documented completely (yet!)  

Here is a sample XAML of what I am talking about:

<Grid
 xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:mc="
http://schemas.openxmlformats.org/markup-compatibility/2006"
 xmlns:d="
http://schemas.microsoft.com/expression/interactivedesigner/2006"
 mc:Ignorable="d"
 Background="#FFFFFFFF"
 x:Name="DocumentRoot"
 Width="640" Height="480" ClipToBounds="False"
>

 <Grid.Resources>
  <Storyboard x:Key="OnLoaded" RepeatBehavior="5x" >
   <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)" Storyboard.TargetName="Rectangle">
     <SplineDoubleKeyFrame d:KeyEase="Linear;Linear;0.5;0.5;0.5;0.5" KeySpline="0.5,0.5,0.5,0.5" Value="360" KeyTime="00:00:02.0" />    
   </DoubleAnimationUsingKeyFrames>
   
   <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)" Storyboard.TargetName="Rectangle2">
    <SplineDoubleKeyFrame d:KeyEase="Linear;Linear;0.5;0.5;0.5;0.5" KeySpline="0.5,0.5,0.5,0.5" Value="360" KeyTime="00:00:02.0" />    
   </DoubleAnimationUsingKeyFrames>   
  </Storyboard>
 </Grid.Resources>

 <Grid.Triggers>
  <EventTrigger RoutedEvent="FrameworkElement.Loaded">
   <BeginStoryboard x:Name="OnLoaded_BeginStoryboard" Storyboard="{DynamicResource OnLoaded}"/>
  </EventTrigger>
 </Grid.Triggers>
 
 <Grid.ColumnDefinitions>
  <ColumnDefinition Width="0.20*"/>
  <ColumnDefinition Width="0.20*"/>
  <ColumnDefinition Width="0.58125*"/>
 </Grid.ColumnDefinitions>
 <Grid.RowDefinitions>
  <RowDefinition Height="0.12*"/>
  <RowDefinition Height="0.12*"/>
  <RowDefinition Height="0.76*"/>
 </Grid.RowDefinitions>
 <Button  HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,0" Width="120" Height="62" Grid.Row="1" Grid.Column="1" ClipToBounds="False" >
  <Rectangle Stroke="#FF000000" Fill="#FFFFFFFF" Width="90" Height="42" x:Name="Rectangle2" RenderTransformOrigin="0.5,0.5">
   <Rectangle.RenderTransform>
    <TransformGroup>
     <RotateTransform Angle="0"/>
    </TransformGroup>
   </Rectangle.RenderTransform>
  </Rectangle>
 </Button>
 
 <Button   HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,0" Width="120" Height="62" Grid.Row="1" Grid.Column="0" ClipToBounds="False" x:Name="Button" >
  <Rectangle Stroke="#FF000000" Fill="#FFFFFFFF" Width="90" Height="42" x:Name="Rectangle" RenderTransformOrigin="0.5,0.5">
   <Rectangle.RenderTransform>
    <TransformGroup>
      <RotateTransform Angle="0"/>
     </TransformGroup>
   </Rectangle.RenderTransform>
  </Rectangle>
 </Button>
</Grid>

**Sorry for lack of graphical creativity, imagine the button is a cool ATM button and the rectangle is an image spinning around telling you "I am doing some work" since the ATM has no cursor ..

If you run it on XAMLPAd or your favorite XAML Editor..  you will see that

1) The rectangle is clipping... why??  Both the Button and the Grid have ClipToBounds = false; it should not be clipping right ?

I use to agree with that until Dmitry, a WPF dev that tends to tolerate all my "dumb questions" around this topic.. shared the skinny... here is a cut & paste from a very old email:

"There are 3 potential sources of clipping behavior for an element:

  1. UIElement.Clip property – you can set whatever geometry there to achieve some interesting clipping. Defaults to nothing
  2. Layout clip – layout is applying clip geometry computed as transformed layout slot (not layout bounds), to make sure the element does not stick out of layout partition reserved by the parent and does not overlap its siblings. Works always, off in Canvas. This is computed in virtual GetLayoutClip
  3. ClipToBounds – when true, sets clip rect equal to Rect(element.RenderSize). Defaults to false.

All of these work independent and result clip is an intersection of all 3 sources."

#1 and #3 are well known ...even I have touched on some (Clipping in particular) …

the missing info is always #2.. LayoutClip?? What is that and where do I get me some? 

Actually, what you need is to get rid of it.. You must override in your FrameworkElement GetLayoutClip () and return either a Geometry big enough for what you are doing, or return null (no clip) … 

The downside  (in my thick headed opinion) is that to get around it, you will have to derive from and override GetLayoutClip ...  afaik, there is not a better way :(  

So, let's give it a shot:  we create a Clipless button .. (UC= UnClipped )

public class UCButton : Button
 {
  protected override Geometry GetLayoutClip ( Size ls )
  {
  return null;
  }
 }

and update our xaml of course now cut & paste into EID or VS2005 since we have code-behind ...

<Grid
 xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:mc="
http://schemas.openxmlformats.org/markup-compatibility/2006"
 xmlns:d="
http://schemas.microsoft.com/expression/interactivedesigner/2006"
 mc:Ignorable="d"
 Background="#FFFFFFFF"
 x:Name="DocumentRoot"
 x:Class="UntitledProject1.Scene1"
 Width="640" Height="480" ClipToBounds="False"
 xmlns:lcl="clr-namespace:UntitledProject1">

 <Grid.Resources>
  <Storyboard x:Key="OnLoaded" RepeatBehavior="5x" >
   <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)" Storyboard.TargetName="Rectangle">
     <SplineDoubleKeyFrame d:KeyEase="Linear;Linear;0.5;0.5;0.5;0.5" KeySpline="0.5,0.5,0.5,0.5" Value="360" KeyTime="00:00:02.0" />    
   </DoubleAnimationUsingKeyFrames>
   
   <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)" Storyboard.TargetName="Rectangle2">
    <SplineDoubleKeyFrame d:KeyEase="Linear;Linear;0.5;0.5;0.5;0.5" KeySpline="0.5,0.5,0.5,0.5" Value="360" KeyTime="00:00:02.0" />    
   </DoubleAnimationUsingKeyFrames>   
  </Storyboard>
 </Grid.Resources>

 <Grid.Triggers>
  <EventTrigger RoutedEvent="FrameworkElement.Loaded">
   <BeginStoryboard x:Name="OnLoaded_BeginStoryboard" Storyboard="{DynamicResource OnLoaded}"/>
  </EventTrigger>
 </Grid.Triggers>
 
 <Grid.ColumnDefinitions>
  <ColumnDefinition Width="0.20*"/>
  <ColumnDefinition Width="0.20*"/>
  <ColumnDefinition Width="0.58125*"/>
 </Grid.ColumnDefinitions>
 <Grid.RowDefinitions>
  <RowDefinition Height="0.12*"/>
  <RowDefinition Height="0.12*"/>
  <RowDefinition Height="0.76*"/>
 </Grid.RowDefinitions>
 <Button  HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,0" Width="120" Height="62" Grid.Row="1" Grid.Column="1" ClipToBounds="False" >
  <Rectangle Stroke="#FF000000" Fill="#FFFFFFFF" Width="90" Height="42" x:Name="Rectangle2" RenderTransformOrigin="0.5,0.5">
   <Rectangle.RenderTransform>
    <TransformGroup>
     <RotateTransform Angle="0"/>
    </TransformGroup>
   </Rectangle.RenderTransform>
  </Rectangle>
 </Button>
 
 <lcl:UCButton   HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,0" Width="120" Height="62" Grid.Row="1" Grid.Column="0" ClipToBounds="False" x:Name="Button" >
  <Rectangle Stroke="#FF000000" Fill="#FFFFFFFF" Width="90" Height="42" x:Name="Rectangle" RenderTransformOrigin="0.5,0.5">
   <Rectangle.RenderTransform>
    <TransformGroup>
      <RotateTransform Angle="0"/>
     </TransformGroup>
   </Rectangle.RenderTransform>
  </Rectangle>
 </lcl:UCButton>
</Grid>

Put it together and you will notice  the first button no longer clips: success:)    

----

I have seen a few  folks doing this really cool "part1, part2" ....  I have not picked any thing deep enough to do that, but today I am still going to fake it ... cause I need to send a more specific answer.. Sam, stay tuned for part2 (20 min or so) ...