I want to have a markup extension called RgbColorExtension
where R
property is bindable to let me adjust its value with a slider.
The following attempt does not work. Changing the slider does not effect the R
property.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Sandbox.MainPage"
xmlns:local="clr-namespace:Sandbox"
>
<VerticalStackLayout>
<Slider x:Name="slider" Maximum="1"/>
<Label Text="{Binding Value,Source={x:Reference slider}}"/>
<BoxView HeightRequest="200" WidthRequest="200">
<BoxView.Color>
<local:RgbColor R="{Binding Value,Source={x:Reference slider}}" G="0" B="0" A="0.5"/>
</BoxView.Color>
</BoxView>
<BoxView
HeightRequest="200"
WidthRequest="200"
Color="{local:RgbColor R={Binding Value,Source={x:Reference slider}},G=0.5,B=0.5,A=.5}"
/>
</VerticalStackLayout>
</ContentPage>
namespace Sandbox;
public class RgbColorExtension : BindableObject, IMarkupExtension<Color>
{
public static readonly BindableProperty RProperty =
BindableProperty.Create(nameof(R), typeof(float), typeof(RgbColorExtension), 0.5f);
public float R
{
get => (float)GetValue(RProperty);
set => SetValue(RProperty, value);
}
public float G { get; set; }
public float B { get; set; }
public float A { get; set; }
public Color ProvideValue(IServiceProvider serviceProvider)
{
return Color.FromRgba(R, G, B, A);
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
}
}
What am I missing here?
If you make your markup extension implement both BindableObject and IMarkupExtension then it will carry its own model. You can declare R, G, B, A as BindableProperties with both getters/setters. You can declare a get only Color property. Then, you make the IMarkupExtension just serve up that final Color property.
/// <summary>
/// Provides the RgbColor XAML markup extension for creating colors from R, G, B, A bindable properties.
/// </summary>
/// <code>
/// >local:RgbColor R="{Binding ...}", G="{Binding ...}", B="{Binding ...}", A="{Binding ...}" /<
/// </code>
[ContentProperty(nameof(R))]
public class RgbColorExtension : BindableObject, IMarkupExtension<BindingBase>
{
public static readonly BindableProperty RProperty = BindableProperty.Create(nameof(R), typeof(float), typeof(RgbColorExtension),
propertyChanged: (b, o, n) => ((RgbColorExtension)b).OnColorChanged());
public float R
{
get { return (float)GetValue(RProperty); }
set { SetValue(RProperty, value); }
}
public static readonly BindableProperty GProperty = BindableProperty.Create(nameof(G), typeof(float), typeof(RgbColorExtension),
propertyChanged: (b, o, n) => ((RgbColorExtension)b).OnColorChanged());
public float G
{
get { return (float)GetValue(GProperty); }
set { SetValue(GProperty, value); }
}
public static readonly BindableProperty BProperty = BindableProperty.Create(nameof(B), typeof(float), typeof(RgbColorExtension),
propertyChanged: (b, o, n) => ((RgbColorExtension)b).OnColorChanged());
public float B
{
get { return (float)GetValue(BProperty); }
set { SetValue(BProperty, value); }
}
public static readonly BindableProperty AProperty = BindableProperty.Create(nameof(A), typeof(float), typeof(RgbColorExtension),
propertyChanged: (b, o, n) => ((RgbColorExtension)b).OnColorChanged());
public float A
{
get { return (float)GetValue(AProperty); }
set { SetValue(AProperty, value); }
}
public Color Color => Color.FromRgba(R / 255f, G / 255f, B / 255f, A / 255f);
public void OnColorChanged() => OnPropertyChanged(nameof(Color));
public object ProvideValue(IServiceProvider serviceProvider)
=> (this as IMarkupExtension<BindingBase>).ProvideValue(serviceProvider);
BindingBase IMarkupExtension<BindingBase>.ProvideValue(IServiceProvider serviceProvider)
=> new Binding(nameof(Color), source: this);
}