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();
}
}
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