views:

163

answers:

2

Hi,

I have a user control that contains an ellipse. The ellipse is translate transformed to the right until it lies partially outside its parent control.

I put the user control into the middle column of a 3 column grid.

If I set the column width to GridUnitType.Auto I can see the ellipse overflowing the column. If I set the column width to GridUnitType.Star the ellipse still overflows the column, but it is now clipped to the column width.

I need to evenly distributed the column widths using GridUnitType.Star, but do not want any transformed content to be clipped.

I've included the sample code below. Any help would be appreciated.

UserControl (containing ellipse)

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="GridWidthTest.UserControl1">

<Grid x:Name="LayoutRoot" Background="Green">
    <Ellipse Fill="#FFF40404" Stroke="Black" Grid.Column="1" Width="400" Height="400" RenderTransformOrigin="0.5,0.5">
        <Ellipse.RenderTransform>
            <TransformGroup>
                <TranslateTransform X="200"/>
            </TransformGroup>
        </Ellipse.RenderTransform>
    </Ellipse>          
</Grid>

Parent control (containing the grid)

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GridWidthTest" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="GridWidthTest.MainPage"
Width="640" Height="480" mc:Ignorable="d">

<Grid x:Name="LayoutRoot" Background="White">

    <Grid ShowGridLines="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>           

        <local:UserControl1 Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>             
    </Grid>         
</Grid>

A: 

This is farily tricky problem to solve. First its important to understand what RenderTransform actually does. It transforms what has been rendered. Each pixel is shifted to a new position based on what is ultimately a fairly simple matrix calculation. This happens quite late in the whole rendering process. The ellipse has already been clipped before the transform is applied.

The layout engine goes through two phases, measure where elements vie for their prefered conditions (the ellipse wants a 400 x 400 box to render in) then arrange where the elements are told by their containers what they can actually have.

In the case where the column width is "Auto" the Grid yields to the UserControl request during the measure phase for a box of width 400. The ellipse renders without any clipping because the box is big enough then the RenderTransform translates the results to a new position.

In the case where the column width is "*" the Grid will only give the UserControl a box of a width determined by that column's share of the available width even if that is less than the UserControl desired width. In this case the ellipse renders but has to clip to the border of the box specified. Its then that this clipped ellipse is translated to a new position.

To be able to break out of the given box an element can specify negative margins. This will result in a larger box to render in. For example if the container indicates that the width is only 200 but the UserControl has a -100 margin the actual box rendered in is 400 pixels wide.

Getting this to work as expected whilst also supporting dynamically arranging content can be a bit of trial and error exercise.

AnthonyWJones
A: 

Thanks for the reply.

I've now resolved this issue by wrapping the ellipse in a canvas, which means it does not get clipped.

Finch