I'm working on a .NET MAUI 9 application and running into a problem with binding when using RelativeSource
while setting x:DataType
in XAML. Specifically, when I try to bind a command in my ContentPage
to a button using RelativeSource
, I get an error during the release build. The error mentions "Invalid IL code" during InitializeComponent
unless I set XamlCompilationOptions.Skip
.
Here's the code I am working with:
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="entities:Person">
<!-- Person Frame -->
<Border
Margin="{StaticResource PersonFrameMargin}"
Padding="{StaticResource PersonFramePadding}"
Background="{StaticResource LightGradientBackground}">
<Border.StrokeShape>
<RoundRectangle CornerRadius="{StaticResource PersonFrameRadius}" />
</Border.StrokeShape>
<!-- Person Grid -->
<Grid Margin="{StaticResource PersonGridMargin}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<!-- Circular Person Image -->
<Border
Grid.Column="0"
Margin="{StaticResource PersonImageMargin}"
Background="{StaticResource LightGradientBackground}"
HeightRequest="{StaticResource PersonImageSize}"
HorizontalOptions="Center"
VerticalOptions="Start"
WidthRequest="{StaticResource PersonImageSize}">
<Border.StrokeShape>
<RoundRectangle CornerRadius="{StaticResource PersonImageCornerRadius}" />
</Border.StrokeShape>
<Image
Aspect="AspectFill"
HeightRequest="{StaticResource PersonImageSize}"
WidthRequest="{StaticResource PersonImageSize}">
<Image.Source>
<MultiBinding Converter="{StaticResource ByteArrayAndGenderToImageSourceConverter}">
<Binding Path="Image.Value" />
<Binding Path="Gender" />
</MultiBinding>
</Image.Source>
</Image>
</Border>
<!-- Person Name And Date StackLayout -->
<StackLayout Grid.Column="1" Spacing="{StaticResource PersonNameAndDateStackLayoutSpacing}">
<Label
FontAttributes="Bold"
FontSize="Large"
LineBreakMode="WordWrap"
Text="{Binding FullName}" />
<Label FontSize="Medium" Text="{Binding LastInquiringDate.Value, StringFormat={StaticResource PersonDateFormat}}" />
</StackLayout>
<!-- Person Round Edit Button -->
<Button
Grid.Column="2"
Margin="{StaticResource PersonRoundEditButtonMargin}"
Command="{Binding Source={RelativeSource AncestorType={x:Type ContentPage}}, Path=BindingContext.EditPersonCommand}"
CommandParameter="{Binding Id}"
CornerRadius="{StaticResource PersonRoundEditButtonRadius}"
HeightRequest="{StaticResource PersonRoundEditButtonSize}"
ImageSource="pencil.png"
VerticalOptions="Start"
WidthRequest="{StaticResource PersonRoundEditButtonSize}" />
<!-- Phone Numbers StackLayout -->
<StackLayout
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3">
<BoxView
Margin="{StaticResource LineMargin}"
Background="{StaticResource White}"
HeightRequest="{StaticResource LineSize}" />
<!-- Phone Numbers Label -->
<Label FontSize="Large" Text="Phone Numbers:" />
<!-- Phone Numbers StackLayout -->
<CollectionView ItemsSource="{Binding PhoneNumbers}" SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="entities:PhoneNumber">
<!-- Phone Grid -->
<Grid Margin="{StaticResource PhoneGridMargin}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<!-- Phone Numbers -->
<Label
Grid.Column="0"
FontAttributes="Bold"
FontSize="Medium"
Text="{Binding FullNumber}"
VerticalOptions="Center" />
<!-- WhatsApp Button -->
<ImageButton
Grid.Column="1"
Command="{Binding Path=BindingContext.SendWhatsAppMessagesCommand, Source={RelativeSource AncestorType={x:Type ContentPage}}}"
CommandParameter="{Binding}"
HeightRequest="{StaticResource WhatsAppButtonSize}"
HorizontalOptions="End"
Source="whatsapp_icon.png"
WidthRequest="{StaticResource WhatsAppButtonSize}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</Grid>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
More specifically the Edit
button:
<!-- Person Round Edit Button -->
<Button
Grid.Column="2"
Margin="{StaticResource PersonRoundEditButtonMargin}"
Command="{Binding Source={RelativeSource AncestorType={x:Type ContentPage}}, Path=BindingContext.EditPersonCommand}"
CommandParameter="{Binding Id}"
CornerRadius="{StaticResource PersonRoundEditButtonRadius}"
HeightRequest="{StaticResource PersonRoundEditButtonSize}"
ImageSource="pencil.png"
VerticalOptions="Start"
WidthRequest="{StaticResource PersonRoundEditButtonSize}" />
The problem arises because I need to use RelativeSource
to bind a command from the ContentPage
's BindingContext
, but I also have x:DataType
set for type safety and the need to pass the Person
's Id
along with the command. When I don't disable XAML compilation by using:
<MauiEnableXamlCBindingWithSourceCompilation>false</MauiEnableXamlCBindingWithSourceCompilation>
The solution won't build and throws XC0045
error.
Steps to reproduce:
x:DataType
on the ContentPage
.BindingContext
of an ancestor element using RelativeSource
like shown above.What I've tried:
MauiEnableXamlCBindingWithSourceCompilation
to false
, but this causes performance issues and I don't want to leave this disabled.<TrimMode>partial</TrimMode>
<Optimize>false</Optimize>
<AndroidLinkMode>None</AndroidLinkMode>
However, these changes did not resolve the issue.
Expected behavior: The binding should work without needing to disable XAML compilation and should allow the command to be bound correctly from the ViewModel.
Question:
Is there a way to correctly use RelativeSource
binding with x:DataType
in .NET MAUI 9 without encountering the "Invalid IL code" error in release builds? If not, is there a workaround to avoid disabling XAML compilation?
Update:
Using inline x:DataType
as Jon Skeet suggested does remove the XC0045
error when building.
I will update the solution and test the release
build again, and then I will update this question accordingly.
The issue I encountered in my .NET MAUI 9 application was caused by two separate problems, both related to binding and XAML compilation. I will break down the solutions for each problem below:
The first issue was the "Invalid IL Code" error that occurred during the release build. This problem was caused by using StaticResource
bindings for properties like:
<Thickness x:Key="RoundButtonsMargin">5,10</Thickness>
<x:Double x:Key="RoundButtonsSize">50</x:Double>
<x:Int32 x:Key="RoundButtonsRadius">25</x:Int32>
and binding them like this:
<Button
Grid.Column="1"
Margin="{StaticResource RoundButtonsMargin}"
Command="{Binding CancelCommand}"
CornerRadius="{StaticResource RoundButtonsRadius}"
HeightRequest="{StaticResource RoundButtonsSize}"
ImageSource="cancel.png"
WidthRequest="{StaticResource RoundButtonsSize}" />
The fix for this issue was removing the usage of the static resources (RoundButtonsMargin
and RoundButtonsRadius
). Once I removed these static resource bindings, the "Invalid IL Code" error during the release build was resolved. After making this change, the app started successfully without throwing the error at runtime
.
I still might need to do more tests to see if the issue relates to using mismatched data types (e.g., using Single
instead of Double
).
The second issue I encountered was the XC0045 error when building the solution, which was related to the use of x:DataType
in conjunction with RelativeSource
.
To resolve this error, I followed Jon Skeet's suggestion to use inline x:DataType
within the Path
instead of separately binding it with AncestorType
only, which fixed the error. Jon mentioned that when using RelativeSource
with an AncestorType
that isn’t element-derived, MAUI automatically uses the FindAncestorBindingContext
mode. He recommended binding directly to the view model instead of accessing the BindingContext
through RelativeSource
, and using inline x:DataType
for clarity and to resolve the issue.
Here's how I modified the code:
Instead of:
<Button
Grid.Column="2"
Margin="{StaticResource PersonRoundEditButtonMargin}"
Command="{Binding Source={RelativeSource AncestorType={x:Type ContentPage}}, Path=BindingContext.EditPersonCommand}"
CommandParameter="{Binding Id}"
CornerRadius="{StaticResource PersonRoundEditButtonRadius}"
HeightRequest="{StaticResource PersonRoundEditButtonSize}"
ImageSource="pencil.png"
VerticalOptions="Start"
WidthRequest="{StaticResource PersonRoundEditButtonSize}" />
I used:
<Button
Grid.Column="2"
Margin="{StaticResource PersonRoundEditButtonMargin}"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:OverdueInquiringViewModel}}, Path=EditPersonCommand, x:DataType=viewmodels:OverdueInquiringViewModel}"
CommandParameter="{Binding Id}"
CornerRadius="{StaticResource PersonRoundEditButtonRadius}"
HeightRequest="{StaticResource PersonRoundEditButtonSize}"
ImageSource="pencil.png"
VerticalOptions="Start"
WidthRequest="{StaticResource PersonRoundEditButtonSize}" />
Using inline x:DataType
for the Command
binding resolved the XC0045 error and allowed the solution to build successfully.
RoundButtonsMargin
and RoundButtonsRadius
. Removing these bindings resolved the error.x:DataType
for the Command
binding, as suggested by Jon Skeet.With these two changes, my app now builds correctly in release mode without requiring XamlCompilationOptions.Skip
.