Controls

Image

Image is the lightweight control for presenting an ImageSource inside the WPF-style UI tree. It has no child content model and no managed drawing mode. Its job is to resolve a source, use that source's pixel size for layout when available, and draw the resulting texture into its arranged slot with the inherited stretch rules.

Quick start

Use Image when you already have an ImageSource contract for a texture or URI-backed asset and you want a normal framework element that participates in layout, alignment, clipping, styling, and opacity.

Minimal XAML image

<Image Width="96"
       Height="96"
       Source="avatars/player-1"
       Stretch="Uniform" />

Thumbnail crop-style presentation

<Border Width="160"
        Height="96"
        BorderBrush="#35516B"
        BorderThickness="1">
  <Image Source="art/cards/mission-brief"
         Stretch="UniformToFill" />
</Border>

Assign a texture in code

namespace InkkSlinger;

public partial class ProfileView : UserControl
{
    private readonly Image? _portrait;

    public ProfileView()
    {
        InitializeComponent();
        _portrait = this.FindName("PortraitImage") as Image;
    }

    public void SetPortrait(Texture2D texture)
    {
        _portrait!.Source = ImageSource.FromTexture(texture);
    }
}

Default recommendation: use ImageSource.FromTexture(...) when you already own a Texture2D. Use URI-backed sources only after you have configured ImageSource.UriSourceResolver for your application.

Source model

Image exposes a single content-like property: Source. The property type is ImageSource, not a WPF bitmap class. The control inherits its entire presentation contract from that source object.

Texture-backed source

ImageSource.FromTexture(texture) gives the control both a real renderable texture and a natural pixel size immediately. This is the most direct and predictable path.

URI-backed source

ImageSource.FromUri(uri) stores a URI string and resolves it later through ImageSource.UriSourceResolver. In XAML, a raw string assigned to Source is converted to this form automatically.

Pixel-only source

ImageSource.FromPixels(width, height) provides layout size without a texture. It is useful for placeholders, sizing contracts, or tests, but it does not produce visible pixels by itself.

  • If Source is null, the control has no intrinsic size and draws nothing.
  • If a URI-backed source cannot resolve to a valid pixel-sized surface, the control behaves as unresolved and does not contribute intrinsic image size.
  • The control clears its cached URI resolution when Source changes.

Raw XAML string to URI-backed source

<Image Source="ui/icons/warning"
       Width="20"
       Height="20" />

That markup is treated as an ImageSource value by the XAML loader, which converts the raw string into ImageSource.FromUri(...) before the property is applied.

Configure a URI resolver once

ImageSource.UriSourceResolver = uri =>
    ImageSource.FromTexture(Content.Load<Texture2D>(uri));

Resolver contract: the framework does not ship a built-in asset pipeline for ImageSource.FromUri(...). Your application decides how URI strings map to textures.

Layout and sizing behavior

Image inherits from SurfacePresenterBase. Measure and arrange use the resolved source's natural pixel size, then apply Stretch and StretchDirection to fit the image into the arranged slot.

Measure

If the source resolves to a pixel size, that natural size becomes the desired size after stretch scaling is computed against the available size. If no pixel size is available, desired size falls back to zero intrinsic image size.

Arrange

The rendered image rectangle is centered inside the final slot after scaling. The control keeps a clip equal to its layout slot, so drawing does not bleed outside the arranged bounds.

  • Stretch="None" keeps the natural pixel size.
  • Stretch="Fill" scales width and height independently to fill the slot.
  • Stretch="Uniform" preserves aspect ratio and fits entirely inside the slot.
  • Stretch="UniformToFill" preserves aspect ratio and fills the slot, which can crop against the layout clip.
  • StretchDirection="UpOnly" prevents downscaling below 1x.
  • StretchDirection="DownOnly" prevents upscaling above 1x.

Preserve the whole image

<Image Width="320"
       Height="180"
       Source="art/loading-screen"
       Stretch="Uniform"
       StretchDirection="Both" />

Avoid enlarging small icons

<Border Width="48"
        Height="48"
        Background="#101822">
  <Image Source="ui/icons/pin"
         Stretch="Uniform"
         StretchDirection="DownOnly" />
</Border>

In that second example, a smaller icon can shrink to fit but will not be scaled up beyond its natural pixel size.

Rendering behavior

The render path is intentionally narrow. Image draws one texture into one computed rectangle. There is no built-in tiling, brush model, nine-slice scaling, or child composition behavior on this control.

When pixels appear

The control renders only when the resolved ImageSource contains a non-null Texture2D. A pixel-only source still affects layout, but it does not draw.

Opacity and clipping

The normal element Opacity value is applied when the texture is drawn. Rendering is clipped to the control's layout slot, which is especially visible with UniformToFill.

  • Source changes invalidate both measure and rendering through the dependency property metadata on Source.
  • URI-backed resolution is cached per requested source instance until the Source property changes.
  • The final texture rectangle is centered inside the arranged slot.

Fade an image with normal element opacity

<Image Source="gallery/cover-01"
       Width="240"
       Height="135"
       Stretch="UniformToFill"
       Opacity="0.72" />

Property reference

Image-specific property

Source: the ImageSource to resolve and present. This can come from ImageSource.FromTexture(...), ImageSource.FromUri(...), ImageSource.FromPixels(...), or a raw XAML string that converts to a URI-backed source.

Inherited presentation properties

Stretch: scaling mode inside the arranged slot. Supported values are None, Fill, Uniform, and UniformToFill.

StretchDirection: scaling constraint. Supported values are Both, UpOnly, and DownOnly.

Common layout properties

Width, Height, MinWidth, and MinHeight can reserve space even when the source is unresolved or when you intentionally want a fixed slot.

Inherited visual properties

Opacity affects the final texture draw. Standard framework alignment and margin properties still apply because Image is a normal FrameworkElement.

Image is a presenter, not a content host. It does not expose a child collection, overlay slot, or template-owned drawing callback like RenderSurface.

Patterns and examples

Avatar inside framed chrome

<Border Width="88"
        Height="88"
        BorderBrush="#4FC7C1"
        BorderThickness="1"
        Padding="4">
  <Image x:Name="PortraitImage"
         Source="avatars/scout"
         Stretch="UniformToFill" />
</Border>

Banner art that fills the card

<Grid Width="320" Height="140">
  <Image Source="banners/season-05"
         Stretch="UniformToFill"
         Opacity="0.85" />
  <Border Background="#66081119" />
  <TextBlock Text="Season Five"
             Margin="16"
             VerticalAlignment="Bottom" />
</Grid>

Reserve layout while the asset loads

var image = new Image
{
    Width = 320,
    Height = 180,
    Source = ImageSource.FromPixels(320, 180)
};

// Later, once the texture is available:
image.Source = ImageSource.FromTexture(texture);

Swap sources without changing the view structure

private void ShowPreview(Texture2D texture)
{
    PreviewImage.Source = ImageSource.FromTexture(texture);
}

private void ClearPreview()
{
    PreviewImage.Source = null;
}

Bind a view-model-provided source

<Image Width="200"
       Height="112"
       Source="{Binding SelectedPreview}"
       Stretch="Uniform" />

That binding works when SelectedPreview resolves to an ImageSource instance. If your view model exposes a string URI instead, convert it before binding or expose an ImageSource-typed property directly.

Notes and pitfalls

Source is not a WPF BitmapImage pipeline. This control expects ImageSource. The supported factories are texture-backed, URI-backed, and pixel-only sources.

URI strings do nothing until you provide a resolver. XAML can convert a string to ImageSource.FromUri(...), but actual texture loading depends entirely on ImageSource.UriSourceResolver.

ImageSource.FromPixels(...) affects layout only. It is useful for placeholders and tests, but the control will not render visible pixels until the source resolves to a real texture.

No child content model. If you need captions, overlays, badges, or chrome, compose them around the Image with a Grid, Border, or other container rather than expecting the control to host children.

Clipping comes from the layout slot. When you use UniformToFill, the oversized portions are clipped by the control bounds, not by a special crop API.