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?
Since you have 4 parameters, you can have your IMarkupExtension
implement (1) BindableObject
(which you've already done so), (2) MultiBinding
, with (3) an IMultiValueConverter
. The 4 float
values can participate in the MultiBinding
and the IMultiValueConverter
converts those 4 float
values into a Color
value.
Here's a working implementation:
[ContentProperty("R")]
public class RgbColorExtension : BindableObject, IMarkupExtension<BindingBase>, IMultiValueConverter
{
public static readonly BindableProperty RProperty
= BindableProperty.Create(nameof(R), typeof(float), typeof(RgbColorExtension));
public static readonly BindableProperty GProperty
= BindableProperty.Create(nameof(G), typeof(float), typeof(RgbColorExtension));
public static readonly BindableProperty BProperty
= BindableProperty.Create(nameof(B), typeof(float), typeof(RgbColorExtension));
public static readonly BindableProperty AProperty
= BindableProperty.Create(nameof(A), typeof(float), typeof(RgbColorExtension));
public float R
{
get { return (float)GetValue(RProperty); }
set { SetValue(RProperty, value); }
}
public float G
{
get { return (float)GetValue(GProperty); }
set { SetValue(GProperty, value); }
}
public float B
{
get { return (float)GetValue(BProperty); }
set { SetValue(BProperty, value); }
}
public float A
{
get { return (float)GetValue(AProperty); }
set { SetValue(AProperty, value); }
}
public object ProvideValue(IServiceProvider serviceProvider)
{
return (this as IMarkupExtension<BindingBase>).ProvideValue(serviceProvider);
}
BindingBase IMarkupExtension<BindingBase>.ProvideValue(IServiceProvider serviceProvider)
{
return new MultiBinding()
{
Converter = this,
Mode = BindingMode.OneWay,
Bindings = new Collection<BindingBase>
{
new Binding(nameof(R), BindingMode.OneWay, null, null, null, this),
new Binding(nameof(G), BindingMode.OneWay, null, null, null, this),
new Binding(nameof(B), BindingMode.OneWay, null, null, null, this),
new Binding(nameof(A), BindingMode.OneWay, null, null, null, this)
}
};
}
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
float R = (float)values[0];
float G = (float)values[1];
float B = (float)values[2];
float A = (float)values[3];
return Color.FromRgba(R, G, B, A);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}