I am trying to figure out what I am doing wrong while creating a custom .NET MAUI control using ContentView. I have read through the docs many times but I still can’t get it to behave as I would expect it to. It is possible that I am expecting the wrong outcome. I am writing this control entirely in C# without XAML and I am using the CommunityToolkit.Maui.Markup package to bind to the component. The custom control is defined like so:
public partial class Elevation : ContentView
{
public static readonly BindableProperty TapCommandProperty = BindableProperty.Create(
nameof(TapCommand),
typeof(ICommand),
typeof(Elevation),
default(ICommand));
public ICommand TapCommand
{
get => (ICommand)GetValue(TapCommandProperty);
set => SetValue(TapCommandProperty, value);
}
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create(
nameof(CornerRadius),
typeof(CornerRadius),
typeof(Elevation),
new CornerRadius(5));
public CornerRadius CornerRadius
{
get => (CornerRadius)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
new public static readonly BindableProperty ShadowProperty = BindableProperty.Create(
nameof(Shadow),
typeof(Shadow),
typeof(Elevation),
new Shadow());
new public Shadow Shadow
{
get => (Shadow)GetValue(ShadowProperty);
set => SetValue(ShadowProperty, value);
}
public Elevation()
{
Content = new Border()
{
Content = Content
}.Bind(PaddingProperty, nameof(Padding), source: this)
.Bind(BackgroundColorProperty, nameof(BackgroundColor), source: this)
.Bind(ShadowProperty, nameof(Shadow), source: this)
.Bind(Border.StrokeShapeProperty, nameof(CornerRadius), source: this, converter: new CornerRadiusToRoundRectangleConverter());
}
}
public class CornerRadiusToRoundRectangleConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is CornerRadius cornerRadius)
{
return new RoundRectangle { CornerRadius = cornerRadius };
}
return new RoundRectangle { CornerRadius = new CornerRadius(5) };
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And this is how I would expect to use it based on what I have read/learned so far:
new Elevation()
{
Padding = 10,
CornerRadius = new CornerRadius(5, 30, 5, 30),
TapCommand = new Command(new Action(() => {})),
Content = new Grid()
{
Children =
{
new Grid()
{
ColumnDefinitions = Columns.Define(25, Star, Star),
Children =
{
new Label()
.Text("Hello")
.Font(size: 18)
.Column(1),
new MauiIcon()
.End()
.CenterVertical()
.Icon(FontAwesomeSolidIcons.ChevronRight)
.IconSize(12.5)
.Column(2)
}
}
}
}
}.AppThemeColorBinding(
BackgroundColorProperty,
Colors.Black,
Colors.White);
The Padding and BackgroundColor properties are being applied properly and are visible in the UI but the Shadow and StrokeShape properties are not reflected in the UI. I am also not confident that I am using the Content property correctly. Any thoughts here as I am out of ideas?
2
Since you use the Border
control as the Content of the Elevation, my advice is to let the Elevation
implement Border
. Then you don’t have to create some BindableProperty
such as Shadow
as Border
has already owned them. Also, I will just define the Content in Elevation
,
public partial class Elevation : Border
{
public static readonly BindableProperty TapCommandProperty = BindableProperty.Create(
nameof(TapCommand),
typeof(ICommand),
typeof(Elevation),
default(ICommand));
public ICommand TapCommand
{
get => (ICommand)GetValue(TapCommandProperty);
set => SetValue(TapCommandProperty, value);
}
public Elevation()
{
Content = new Grid()
{
Children =
{
new Grid()
{
ColumnDefinitions = Columns.Define(25, Star, Star),
Children =
{
new Label()
.Text("Hello")
.Font(size: 18)
.Column(1),
new MauiIcon()
.End()
.CenterVertical()
.Icon(FontAwesomeSolidIcons.ChevronRight)
.IconSize(12.5)
.Column(2)
}
}
}
};
}
}
And when you want to consume it, just use the code like
Elevation e = new Elevation()
{
Padding = 10,
TapCommand = new Command(new Action(() => { })),
StrokeShape = new RoundRectangle() { CornerRadius = new CornerRadius(5,30,5,30)}
};
Of course, you don’t need a Converter any more.
For more info, you may refer to Border. Please let me know if you have any question.
1