I'm attempting to try my hand at creating a card-based UI similar to Android's CardView
layout using MAUI ContentView
. The exemplary use case for such an element is the display of testing or scoring results, so I attempted to roll in some of the underlying logic directly into the new element - the user would simply have to supply an Attempted
and a Possible
set of integers, i.e. 92
and 100
, from which it would display an "out-of" format of 92/100
as well as a percentage of 92.0%
.
The issue is that I've tried a number of ways to do this, and none successfully update the Score
and Percentage
properties correctly. I realize that it may be an issue with the order (or simultaneity) of the properties being set, but I haven't been able to rectify it using BindableProperty.Create(..., propertyChanged:)
or other methods.
ProgressViewCard.xaml
:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView x:Name="this"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ExampleApp.Controls.ProgressCardView">
<Frame BindingContext="{x:Reference this}" BackgroundColor="{Binding BackgroundColor}" CornerRadius="5" HasShadow="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="3*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<!-- Configure the button functionality of the ProgressCardView -->
<Button x:Name="InternalButton" Grid.RowSpan="3" Grid.ColumnSpan="2" Opacity="0.0" Clicked="buttonEvent" />
<Label Text="{Binding Title}" HorizontalOptions="Start" VerticalOptions="Center" FontSize="17" TextColor="{Binding HeaderColor}" />
<Label Text="{Binding Score}" Grid.Column="1" Grid.ColumnSpan="2" HorizontalOptions="End" VerticalOptions="Center" FontSize="12" TextColor="{Binding TextColor}" />
<BoxView Grid.Row="1" Grid.ColumnSpan="3" HeightRequest="1" Color="{Binding TextColor}"/>
<ProgressBar x:Name="CardProgressBar" Grid.Row="2" Grid.ColumnSpan="2" />
<Label Text="{Binding Percentage}" Grid.Row="2" Grid.Column="2" HorizontalOptions="End" VerticalOptions="Center" FontSize="12" TextColor="{Binding TextColor}" />
</Grid>
</Frame>
</ContentView>
ProgressViewCard.xaml.cs
:
namespace ExampleApp.Controls
{
public partial class ProgressCardView : ContentView
{
private int attempted = 0;
private int possible = 0;
#region BindableProperties
public static readonly BindableProperty TitleProperty = BindableProperty.Create(
nameof(Title),
typeof(string),
typeof(ProgressCardView2),
string.Empty);
public static readonly BindableProperty AttemptedProperty = BindableProperty.Create(
nameof(Attempted),
typeof(int),
typeof(ProgressCardView2),
0);
public static readonly BindableProperty PossibleProperty = BindableProperty.Create(
nameof(Possible),
typeof(int),
typeof(ProgressCardView2),
1);
public static readonly BindableProperty BackgroundColorProperty = BindableProperty.Create(
nameof(BackgroundColor),
typeof(Color),
typeof(ProgressCardView2),
Color.FromArgb("#FFFFFF"));
public static readonly BindableProperty HeaderColorProperty = BindableProperty.Create(
nameof(HeaderColor),
typeof(Color),
typeof(ProgressCardView2),
Color.FromArgb("#FFFFFF"));
public static readonly BindableProperty TextColorProperty = BindableProperty.Create(
nameof(TextColor),
typeof(Color),
typeof(ProgressCardView2),
Color.FromArgb("#FFFFFF"));
#endregion
#region Getters and Setters
public string Title
{
get => (string) GetValue(ProgressCardView2.TitleProperty);
set => SetValue(ProgressCardView2.TitleProperty, value);
}
public int Attempted
{
get => (int) GetValue(ProgressCardView2.AttemptedProperty);
set => SetValue(ProgressCardView2.AttemptedProperty, value);
}
public int Possible
{
get => (int)GetValue(ProgressCardView2.PossibleProperty);
set => SetValue(ProgressCardView2.PossibleProperty, value);
}
public string Score
{
get { return String.Format("{0}/{1}", this.attempted, this.possible); }
set { this.Score = value; }
}
public string Percentage
{
get { return String.Format("{0:P1}", ((double) this.attempted) / ((double) this.possible)); }
set { this.Score = value; }
}
public Color BackgroundColor
{
get => (Color) GetValue(ProgressCardView2.BackgroundColorProperty);
set => SetValue(ProgressCardView2.BackgroundColorProperty, value);
}
public Color HeaderColor
{
get => (Color) GetValue(ProgressCardView2.HeaderColorProperty);
set => SetValue(ProgressCardView2.HeaderColorProperty, value);
}
public Color TextColor
{
get => (Color) GetValue(ProgressCardView2.TextColorProperty);
set => SetValue(ProgressCardView2.TextColorProperty, value);
}
#endregion
#region Methods and Events
public ProgressCardView2()
{
InitializeComponent();
}
private void buttonEvent(object sender, EventArgs e)
{
}
#endregion
}
}
The usage of the controls is as follows:
<ctrls:ProgressCardView Title="CS 101 Final" Attempted="92" Possible="100" BackgroundColor="#ffffff"
HeaderColor="#e74c3c" TextColor="#7f8c8d" />
<ctrls:ProgressCardView Title="ME 302 Midterm" Attempted="68" Possible="85" BackgroundColor="#ffffff"
HeaderColor="#e74c3c" TextColor="#7f8c8d" />
This is the result in an Android emulator (API 31). How do I modify the above control to obtain the correct behavior?