ygoe
ygoe

Reputation: 20414

Manually layout an image in WPF

My application has some space in a XAML window where an image must be displayed. The image is generated whenever the size of the available space changes. This doesn't quite work yet.

I can place an Image control but it will either scale its content (forbidden!) or auto-size to the current image (will never tell me the available space).

I've tried with this:

<Grid Name="ImageContainer" Grid.Row="1">
    <Image
        Width="{Binding ActualWidth, ElementName=ImageContainer}"
        Height="{Binding ActualHeight, ElementName=ImageContainer}"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Source="/Images/dummy_filler_icon.png"
        Stretch="None"
        SizeChanged="GraphImage_SizeChanged"/>
</Grid>

It doesn't work either. The Width and Height setting is completely ignored. The Image will always be as large as the current source. Also I need to set an initial source so that the Image has any size at all.

So what I need is a way to let XAML layout a fixed space in a Grid layout or whatever, then tell me what size it has so that I can generate that bitmap image and somehow bring it onto the screen. As soon as that layout space changes its size, a new image must be generated and displayed.

Can this be done with WPF?

With HTML/CSS I'd just use an empty <div> element (let's say it's a <Grid> in WPF), add a resize event handler, query the current size, and place the generated bitmap as its background. But you can't just spread images anywhere in WPF, you need an Image control for that. But WPF's Image control is too stubborn for this simple method.

Also, the whole thing is inside a <DataTemplate> so I cannot access named elements from code-behind. I can only access them through the sender parameter of event handlers. I need to access their DataContext because that's where the source data is which is used in the generated image.

Upvotes: 0

Views: 641

Answers (1)

Clemens
Clemens

Reputation: 128136

You could use a Rectangle instead of an Image control, and set its Fill property to an ImageBrush with an appropriately sized ImageSource in a SizeChanged handler:

<Grid>
    <Rectangle SizeChanged="GraphImage_SizeChanged"/>
</Grid>

Code behind:

private void GraphImage_SizeChanged(object sender, SizeChangedEventArgs e)
{
    // create a bitmap with appropriate size
    var bitmap = new WriteableBitmap(
        (int)e.NewSize.Width, (int)e.NewSize.Height, 96, 96, PixelFormats.Rgb24, null);
    ...

    var rectangle = (Rectangle)sender;
    rectangle.Fill = new ImageBrush(bitmap);
}

Upvotes: 2

Related Questions