Search code examples
c#mauimaui-community-toolkit

.NET Maui binding displays data on debug mode but not on release mode


I'm developing an app in .NET Maui and testing in a Android 14 phone, when I run it in debug mode data is displayed correctly, but when in Release mode data in the ClassNameView custom view and in the CollectionView is blank, I know that data is being loaded correctly, at least for the CollectionView, because there are as many rows as it should, but data is blank, if I put the XML of the custom view directly in the page then data is displayed as it should

What am I missing?

ObservationHistoryPage.xaml

<ContentPage
    x:Class="SchoolApp.Views.ObservationHistoryPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:custom="clr-namespace:SchoolApp.Custom"
    xmlns:resx="clr-namespace:SchoolApp.Resources.Strings"
    xmlns:skia="clr-namespace:SkiaSharp.Extended.UI.Controls;assembly=SkiaSharp.Extended.UI"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    xmlns:vm="clr-namespace:SchoolApp.ViewModels"
    Title="{x:Static resx:AppResources.ObservationsHistory}"
    x:DataType="vm:ObservationHistoryPageViewModel">
    <ContentPage.Behaviors>
        <toolkit:EventToCommandBehavior Command="{Binding NavigatedToCommand}" EventName="NavigatedTo" />
    </ContentPage.Behaviors>
    <Grid>
        <custom:LoadingAndErrorView
            Display="{Binding Display}"
            ErrorDescription="{Binding ErrorMessage}"
            ErrorTitle="{Binding ErrorTitle}"
            RetryCommand="{Binding LoadInfoCommand}" />
        <ScrollView>
            <VerticalStackLayout
                Padding="10"
                IsVisible="{Binding DisplayData}"
                Spacing="10">
                <!--  Class Name  -->
                
                <custom:ClassNameView ClassName="{Binding ClassName}" />
                <Label
                    HorizontalOptions="Center"
                    Style="{StaticResource LargeLabelBold}"
                    Text="{x:Static resx:AppResources.ObservationHistory}" />
               
                <!--  Count  -->
                <HorizontalStackLayout Padding="0,0,5,0" HorizontalOptions="End">
                    <Label Style="{StaticResource MediumLabelItalic}" Text="Total:" />
                    <Label Style="{StaticResource MediumLabelItalic}" Text="{Binding ObservationCount}" />
                </HorizontalStackLayout>
                <!--  Dates  -->
                <CollectionView ItemsSource="{Binding Dates}" SelectionMode="None">
                    <CollectionView.ItemTemplate>
                        <DataTemplate>
                            <Grid Padding="10" ColumnDefinitions="80,*">
                                <Image
                                    HorizontalOptions="Center"
                                    Source="calendar"
                                    WidthRequest="68" />
                                <Label
                                    Grid.Column="1"
                                    HorizontalOptions="Center"
                                    Style="{StaticResource LargeLabelBold}"
                                    Text="{Binding ., StringFormat='{0:dd / MMMM / yyyy }'}"
                                    VerticalOptions="Center" />
                            </Grid>
                        </DataTemplate>
                    </CollectionView.ItemTemplate>
                </CollectionView>
                <!--  close button  -->
                <Button
                    Command="{Binding CloseCommand}"
                    IsVisible="{Binding IsNotBusy}"
                    Style="{x:StaticResource ButtonOutline}"
                    Text="{x:Static resx:AppResources.Close}" />
            </VerticalStackLayout>
        </ScrollView>
    </Grid>
</ContentPage>

ObservationHistoryPageViewModel.cs

using SchoolApp.Models.Observations;

namespace SchoolApp.ViewModels
{
    [QueryProperty(nameof(Observation), nameof(Observation))]
    [QueryProperty(nameof(ClassName), nameof(ClassName))]
    public partial class ObservationHistoryPageViewModel : BaseViewModel
    {
        private readonly ObservationsService _observationsService;
        [ObservableProperty]
        ObservationStudentComplete _observation;
        
        [ObservableProperty]
        string _className;

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(ObservationCount))]
        List<DateTime> _dates=new List<DateTime>();


        public int ObservationCount => Dates.Count;

        public ObservationHistoryPageViewModel(ObservationsService observationsService)
        {
            _observationsService = observationsService;
        }

        [RelayCommand]
        public async Task NavigatedTo()
        {
            await LoadInfo();
        }

        [RelayCommand]
        public async Task LoadInfo()
        {
            SetPageInLoadingState();
            var result = await _observationsService.GetObservationHistory(Selected.Student.IdAlumno, Selected.Organization.IsParent, Observation);
            SetDisplayAndErrorsFromResult(result);
            Dates = result.Item ?? new List<DateTime>();
            SetPageInFinishLoadingState();
        }

        [RelayCommand]
        public async Task Close()
        {
            await Shell.Current.GoToAsync("..");
        }
    }
}

Here is the custom view

ClassNameView.xaml

<Grid
    x:Class="SchoolApp.Custom.ClassNameView"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:custom="clr-namespace:SchoolApp.Custom"
    x:DataType="custom:ClassNameView"
    ColumnDefinitions="80,*">
    <Image Source="books" WidthRequest="60" />
    <Label
        Grid.Column="1"
        Style="{x:StaticResource LargeLabelBold}"
        Text="{Binding ClassName}"
        VerticalOptions="Center" />
</Grid>

ClassNameView.xaml.cs

namespace SchoolApp.Custom;

public partial class ClassNameView : Grid
{
    public static readonly BindableProperty ClassNameProperty = BindableProperty.Create(nameof(ClassName)
        , typeof(string)
        , typeof(ClassNameView)
        , default(string)
        , propertyChanged: (bindable, value, newValue) => ((ClassNameView)bindable).ClassName = (string)newValue);
    public string ClassName
    {
        get => (string)GetValue(ClassNameProperty);
        set => SetValue(ClassNameProperty, value);
    }
    public ClassNameView()
    {
        InitializeComponent();
    }
}

Solution

  • For your empty collection, you should check this: https://stackoverflow.com/a/75285858/6643940

    For your grid control, I have different solution.

    Usually, when you override Grid, you are trying to create control that have different behavior. That is, it will be expected that you can do:

    <MyGrid> <Something> </MyGrid> 
    

    And there would be something different there - either you will have new functionality of grid, or change of existing functionality.

    If you are just trying to make a custom control, that have predefined look, you can simply make control template.

    https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/controltemplate?view=net-maui-8.0

    1. Move your XAML to control template, set the binding context of the grid to templated parent.
    2. Do not override Grid, just ContentView in your control code.
    3. Set the Template key to your page xaml, where you create the control.