Jaime Rodriguez
On Windows Store apps, Windows Phone, HTML and XAML

  • Jaime Rodriguez

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

    • 2 Comments

    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) ...

  • Jaime Rodriguez

    ClipToBounds part2... Applied to ListBox ....

    • 0 Comments

    So, I gave you the secret already ... GetLayoutClip () ...  that is it ...

    MY problem is twice I have sent that answer and they got back to me with "it is still not working" ... mostly because they were trying to do it in a ListBox...  Let's walk through it before we see some code:

    Apply my lazy factor to the scenario:

     This is a listbox with my portfolio ( Stock symbols).. as I MouseOver each ListBox items, it Scales to 150% so I can read the details..  [all you need is to replace the template, for today we will use the same planet datatemplate we used last time, I told you Datatemplates maximized reuse did not I ? 

    Unfortunately, we are not there yet... Right now, the image is being clipped like this and I can't read the (imaginary) details..

     

    So, who is clipping it?  In my experience that varies widely .. 

    To understand why it varies, you must use Reflector and go look at FrameworkElement:GetLayoutClip ...   There are many checks ( MaxWidth/Height) , Margins + RenderSize, etc. that determine what your clip is..  so depending on what you are doing, you might either be clipped by:

    • the ListBox itself,  -- this is almost always true
    • the Panel you are using for your ItemsPanel or ( I don't see this one often)
    • your ListBoxItem.. ( have not seen this a lot other than some creative animations)
    • seldomly your item is clipped in the template itself -for this one do what we did for the button --

    Experience taught me to override all at once; don't leave it to luck or the person replacing you will be puzzled a year from now, when they change some thing in the template and this thing starts clipping ...

    So, attached is a quick & very dirty example -- don't think of it as a best practice, more of a what to look for list' on how to get around some of the usual gotchas..  Here is what it shows:

    1. UCListBox derived from ListBox and override GetLayoutClip ..     (Unclipped.cs)
    2. Override the listBox's ControlTemplate...  The ControlTemplate had a Border, a ScrollViewer, and other items that tend to clip your ListBoxItem.. .(ResourceDictionary1.xaml,  UCListBoxTemplate)
    3. UCListBoxItem derived from ListBoxItem and override GetLayoutClip [ this one I do all the time too, though part of the time you can get away with out it] .. (Unclipped.cs)
      1. Note, if you do that, you need to tell the ListBox ItemGenerator to create your custom ListBoxItems, so override GetContainerForItemOverride ... (Unclipped.cs)
    4. Go back to the XAML and tell it to use my custom UCListBox instead of the ListBox I had earlier ..   ( Scene2.xaml , <lcl:UCListBox Margin... )

     

    OK, I think that is it ... See code attached....  Created using July CTP ... Opens fine in Expression of course..  [but might need to build it once before you can use designer]

     

     

     

     

     

     

     

     

  • Jaime Rodriguez

    rant to self...

    • 0 Comments

    jaime,  3 weeks again with no posts at all.. lame..

     

     

  • Jaime Rodriguez

    Every one wants a Windows Vista sidebar gadget... share your wish...

    • 0 Comments

    Sidebar is one of my favorite features in Vista..  It is just so full of business-value opportunities and it is such a low entry point that every one tends to always love it..

    It is an extension to the existing "enterprise portal" model that has become so popular and successful over the last few years...  but it brings the content to the desktop where I might be able to interact with it in off-line mode or with many less clicks and less overhead than a portal (launch browser, drink a sip, page loads, refresh, etc.) ..  with sidebar it is Windows+SpaceBar and I am there..   

    I should come back to a deeper explanation of what sidebar is.. but in the mean time, start here

    One of my favorite parts of talking about sidebar is that people always have a "must have gadget"... My bro-in-law wants an "ebay gadget" to let him bid and notify him if some one is messing with his (likely to be) new toys; a peer wants an "airline gadget" that tells her when her hubby's plane arrives from business trips... etc.. 

    For me it was weather, with my < 3  year old, I am always looking for when it will be "sunny but not hot" or "at least not raining" so I can plan my outings with him...  a few weeks ago, I wrote my weather gadget ... piece of cake, in a couple hours I was running -and most time it took me to find a weather webservice-..  So, I was looking to be a team player and submit my gadget to the "sidebar gallery"  but I upgraded to Vista RC1 and the gadget is already there..  my contribution opportunity was killed.. 

    My other "must have gadget" is my "Outlook To-Do Bar"... For those running Office 2007, you know what I am talking about..  This gadget tells me where I need to be with out launching Outlook..  it works in cache mode, etc..  Unfortunately, i am more aprehensive to share that because 1) the UI needs polishing.. 2) It is Outlook code, with PIAs, etc. so harder to package and install and I am not sure I can support it or clean it up enough 3) some one has already contributed a similar gadget to the community..  4) with my luck, the office team beats me to it again...

    So, I need ideas.. Share what your "must have gadget" is.. and I might just write it for you.. Here is my only criteria: I always say that "sidebar was designed to simplify your every day tasks" ... so I want some thing you will use a bit.. some thing that saves you 2 minutes of work a few times a day...  

    Actually, a second criteria.. for all those service providers/e-commerce enterprises  working with me on early adoption projects: I am not writing your gadget... [reaching your customers via sidebar gadgets will make you bundals, least you can do is write your own]

    For the rest, I do hope to hear from you ...  I committ to writing one during month of september..  [ likely around the 18th or so, cause I have some committments coming]..

    Thanks,

     

     

     

     

     

     

     

  • Jaime Rodriguez

    You must snoop into your app..

    • 0 Comments

    Via John Gossman...  

    At first, I could not believe this there would be a utlility that helped me troubleshoot my WPF bindings... but snoop does :)  ...

    This also walks you through Visual Tree ( a trick/utlity I use often now a days)

    It just happened that I was messing w/ a dynamic layout for overflow stuff ... and snoop also looks handy because I can check exactly the size of my controls as I resize...

    The direct link is http://www.blois.us/Snoop/ ... Definitely a MUST Download!!

    [back to my overflow problems, using snoop :) ]

     

     

Page 1 of 1 (5 items)