Share via

Adding an Image to a custom control in MAUI

Jai Holloway 110 Reputation points
2026-05-27T10:06:51.6566667+00:00

Hi there

I have been asked to add an image to a view in an old Xamarin app that has been upgraded to MAUI. I am new to MAUI and the custom control is confusing me. I need to add and image placeholder, but set the image source when the form is loaded from a viewmodel. At the moment I have

<?xml version="1.0" encoding="utf-8" ?>
<ContentView  xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TourGrosses.Controls.TourProductItem"
             xmlns:telerik="http://schemas.telerik.com/2022/xaml/maui">
    <Grid Padding="10" BackgroundColor="{AppThemeBinding Light={DynamicResource ArtistSummaryItemBackground}, Dark={DynamicResource ArtistSummaryItemBackgroundDark}}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <telerik:RadBorder CornerRadius="8" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
            <Label x:Name="ProductLabel" 
                   Grid.Row="0" 
                   Grid.Column="0" 
                   Grid.ColumnSpan="2" 
                   HorizontalTextAlignment="Center" 
                   VerticalTextAlignment="Center" 
                   Style="{AppThemeBinding Light={DynamicResource ArtistSummaryTitle}, Dark={DynamicResource ArtistSummaryTitleDark}}" 
                   FontSize="Medium"
                   FontAutoScalingEnabled="False"/>
        </telerik:RadBorder>
        <Image x:Name="ImageIcon" Grid.Row="1" Grid.RowSpan="4" Grid.Column="0"/>
        <Label Text="Qty Sold" 
               Grid.Row="1" 
               Grid.Column="1" 
               Style="{AppThemeBinding Light={DynamicResource TourProductItemLabel}, Dark={DynamicResource TourProductItemLabelDark}}" 
               FontSize="Medium"
               FontAutoScalingEnabled="False"/>
        <Label x:Name="QtySoldLabel" 
               Grid.Row="1" 
               Grid.Column="2" 
               HorizontalTextAlignment="End" 
               Style="{AppThemeBinding Light={DynamicResource TourProductItemValue}, Dark={DynamicResource TourProductItemValueDark}}" 
               FontSize="Medium"
               FontAutoScalingEnabled="False"/>
        <Label Text="Total Sales" 
               Grid.Row="2" 
               Grid.Column="1" 
               Style="{AppThemeBinding Light={DynamicResource TourProductItemLabel}, Dark={DynamicResource TourProductItemLabelDark}}" 
               FontSize="Medium"
               FontAutoScalingEnabled="False"/>
        <Label x:Name="TotalSalesLabel" 
               Grid.Row="2" 
               Grid.Column="2" 
               HorizontalTextAlignment="End" 
               Style="{AppThemeBinding Light={DynamicResource TourProductItemValue}, Dark={DynamicResource TourProductItemValueDark}}" 
               FontSize="Medium"
               FontAutoScalingEnabled="False"/>
        <Label Text="% of Gross" 
               Grid.Row="3" 
               Grid.Column="1" 
               Style="{AppThemeBinding Light={DynamicResource TourProductItemLabel}, Dark={DynamicResource TourProductItemLabelDark}}" 
               FontSize="Medium"
               FontAutoScalingEnabled="False"/>
        <Label x:Name="PercentGrossLabel" 
               Grid.Row="3" 
               Grid.Column="2" 
               HorizontalTextAlignment="End" 
               Style="{AppThemeBinding Light={DynamicResource TourProductItemValue}, Dark={DynamicResource TourProductItemValueDark}}" 
               FontSize="Medium"
               FontAutoScalingEnabled="False"/>
        <Label Text="Ratio" 
               Grid.Row="4" 
               Grid.Column="1" 
               Style="{AppThemeBinding Light={DynamicResource TourProductItemLabel}, Dark={DynamicResource TourProductItemLabelDark}}" 
               FontSize="Medium"
               FontAutoScalingEnabled="False"/>
        <Label x:Name="RatioLabel" 
               Grid.Row="4" 
               Grid.Column="2" 
               HorizontalTextAlignment="End" 
               Style="{AppThemeBinding Light={DynamicResource TourProductItemValue}, Dark={DynamicResource TourProductItemValueDark}}" 
               FontSize="Medium"
               FontAutoScalingEnabled="False"/>
    </Grid>
</ContentView>

But it is not recognising ImageIcon in the form when I try to set the Image to something.

What am I doing wrong?

Developer technologies | XAML
Developer technologies | XAML

A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.

0 comments No comments

Answer accepted by question author

AI answer

2026-05-27T10:07:19.6866667+00:00

ImageIcon is a named element inside a ContentView custom control. To set its image from a viewmodel or from the parent view, expose a bindable property on the ContentView and bind the Image.Source to that property, instead of trying to access ImageIcon directly from outside.

  1. In TourProductItem.xaml, bind the Image to a property on the ContentView:
<ContentView  xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="TourGrosses.Controls.TourProductItem">
    <Grid Padding="10">
        <!-- other rows/columns omitted for brevity -->

        <Image x:Name="ImageIcon"
               Grid.Row="1"
               Grid.RowSpan="4"
               Grid.Column="0"
               Source="{Binding ImageSource, Source={x:Reference this}}" />

        <!-- other labels -->
    </Grid>
</ContentView>

Make sure the root ContentView has a name so it can be referenced:

<ContentView x:Class="TourGrosses.Controls.TourProductItem"
             x:Name="this"
             xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
  1. In TourProductItem.xaml.cs, define a bindable property and CLR wrapper:
public partial class TourProductItem : ContentView
{
    public static readonly BindableProperty ImageSourceProperty =
        BindableProperty.Create(
            nameof(ImageSource),
            typeof(ImageSource),
            typeof(TourProductItem),
            default(ImageSource));

    public ImageSource ImageSource
    {
        get => (ImageSource)GetValue(ImageSourceProperty);
        set => SetValue(ImageSourceProperty, value);
    }

    public TourProductItem()
    {
        InitializeComponent();
    }
}
  1. From the parent page or its viewmodel, set the property instead of the internal ImageIcon:
<!-- In the parent page XAML -->
<controls:TourProductItem ImageSource="dotnet_bot.png" />

or via binding:

<controls:TourProductItem ImageSource="{Binding ProductImage}" />

This pattern matches how custom controls are built with ContentView: internal elements (like ImageIcon) are not accessed directly from outside; instead, bindable properties are exposed and used for data binding.


References:

AI-generated content may be incorrect. Read our transparency notes for more information.

Was this answer helpful?

1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Jack Dang (WICLOUD CORPORATION) 18,720 Reputation points Microsoft External Staff Moderator
    2026-05-27T10:44:45.38+00:00

    Hi @Jai Holloway ,

    Thanks for reaching out.

    The code snippets below are just for reference, so you may need to adjust names, bindings, or project structure details to fit your solution.

    The thing to keep in mind here is that x:Name="ImageIcon" only makes that image available inside the TourProductItem control itself, usually in TourProductItem.xaml.cs. It will not be directly visible from the page or form that is using the custom control.

    In MAUI, the suitable approach is to expose a BindableProperty on the custom control, then bind the internal Image to that property. That way your page or viewmodel can set the image source without needing to reach into the control's internal XAML names.

    For example, in your TourProductItem.xaml, give the root control a name and bind the image source to a property on the control:

    <ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
           xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
           x:Class="TourGrosses.Controls.TourProductItem"
           x:Name="Root"
           xmlns:telerik="http://schemas.telerik.com/2022/xaml/maui">
    
      <Grid Padding="10">
        ...
    
        <Image Grid.Row="1"
             Grid.RowSpan="4"
             Grid.Column="0"
             WidthRequest="80"
             HeightRequest="80"
             Aspect="AspectFit"
             Source="{Binding ProductImageSource, Source={x:Reference Root}}" />
    
        ...
      </Grid>
    </ContentView>
    

    Then add the bindable property in TourProductItem.xaml.cs:

    namespace TourGrosses.Controls;
    
    public partial class TourProductItem : ContentView
    {
      public static readonly BindableProperty ProductImageSourceProperty =
        BindableProperty.Create(
          nameof(ProductImageSource),
          typeof(ImageSource),
          typeof(TourProductItem),
          default(ImageSource));
    
      public ImageSource ProductImageSource
      {
        get => (ImageSource)GetValue(ProductImageSourceProperty);
        set => SetValue(ProductImageSourceProperty, value);
      }
    
      public TourProductItem()
      {
        InitializeComponent();
      }
    }
    

    After that, wherever you use the custom control, you can bind the image from your viewmodel like this:

    <controls:TourProductItem ProductImageSource="{Binding ProductImage}" />
    

    And your viewmodel can expose something like:

    private ImageSource _productImage;
    
    public ImageSource ProductImage
    {
      get => _productImage;
      set
      {
        _productImage = value;
        OnPropertyChanged();
      }
    }
    

    Then when the form loads, you can set it, for example:

    ProductImage = ImageSource.FromFile("placeholder.png");
    

    If the image is bundled with the app, place it under Resources/Images, make sure it is using the MauiImage build action, and reference it by file name.

    Hope this helps! If my explanation and the information I provided were also helpful, I would greatly appreciate it if you could follow the instructions here so others with the same problem can benefit as well.

    Was this answer helpful?


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.