Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF image host with centering and clipping

I feel like I may need some converters, but this is what I want to do. I want a single Image control (since it is in a data template that is bound to real data) with the following parameters.

  • Be centered in a space that is 90x90 (no stretching of any sort).
  • Have a circular clipping of radius 40 pixels (both horizontal and vertical).
  • If image is > 90x90, it should center within the 90x90 space and clip a 40x40 circle from the middle.
  • If image is < 90x90, it should center within the 90x90 space. The clipping circle should have no effect since the entire image is contained within the clip area.

I have my XAML code below. This works as expected for pictures that are exactly 90x90 (i.e. they don't stretch, they center the image and the clipping works). For images > 90x90, the clipping works correctly but the image is not getting centered. For images < 90x90, the image gets centered but the clipping seems to place the image in the top-left area of the Image content so, the clipping clips the top-left portion of the image.

<Style x:Key="ImageStyle">
    <Setter Property="Width" Value="90" />
    <Setter Property="Height" Value="90" />
    <Setter Property="Stretch" Value="None" />
    <Setter Property="HorizontalAlignment" Value="Center" />
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="Clip">
        <Setter.Value>
            <EllipseGeometry Center="45,45" RadiusX="40" RadiusY="40" />
        </Setter.Value>
    </Setter>
</Style>

<Grid>
    <!-- Other Stuff -->
    <Image Source="{Binding ImagePath}" Style="{StaticResource ImageStyle}" />
</Grid>

I can get rid of the second issue (small image clipping) by wrapping in a Grid and moving the clipping there, but large stuff doesn't center:

<Grid>
    <!-- Other Stuff -->
    <Grid Width="90" Height="90">
        <Grid.Clip>
            <EllipseGeometry Center="45,45" RadiusX="40" RadiusY="40" />
        </Grid.Clip>
        <Image Source="{Binding ImagePath}" Style="{StaticResource ImageStyle}" />
    </Grid>
</Grid>
like image 755
sohum Avatar asked Dec 12 '22 07:12

sohum


2 Answers

I ended up having to just remove the Width and Height properties from the Image Style. Looking at it with WPF Snoop, the image is now bigger than the containing Grid but since the Grid has a fixed size, it centers itself on that.

<Style x:Key="ImageStyle">
    <Setter Property="Stretch" Value="None" />
    <Setter Property="HorizontalAlignment" Value="Center" />
    <Setter Property="VerticalAlignment" Value="Center" />
</Style>

<Grid>
    <!-- Other Stuff -->
    <Grid Width="90" Height="90">
        <Grid.Clip>
            <EllipseGeometry Center="45,45" RadiusX="40" RadiusY="40" />
        </Grid.Clip>
        <Image Source="{Binding ImagePath}" Style="{StaticResource ImageStyle}" />
    </Grid>
</Grid>
like image 58
sohum Avatar answered Dec 13 '22 20:12

sohum


The easiest way I've found to center and clip and image is to use a different element, such as a Rectangle, then fill it with an ImageBrush. For example:

<Rectangle>
    <Rectangle.Fill>
        <ImageBrush
            ImageSource="{Binding SomeUriPropertyOrOther}"
            Stretch="UniformToFill"/>
    </Rectangle.Fill>
</Rectangle>

This does centering and clipping. (Irrelevant for Stretch == Fill and Uniform, I guess.)

like image 39
Petter Hesselberg Avatar answered Dec 13 '22 20:12

Petter Hesselberg