I have created a bool to color like this:
public class BoolToColorConverter : BindableObject, IValueConverter
{
public BoolToColorConverter()
{
}
public static readonly BindableProperty TrueColorProperty =
BindableProperty.Create(nameof(TrueColor), typeof(Color), typeof(BoolToColorConverter), null, BindingMode.OneWay, null, null);
public Color TrueColor
{
get { return (Color) GetValue(TrueColorProperty); }
set { SetValue(TrueColorProperty, value); }
}
public Color FalseColor { get; set; } = null!;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool b && b)
{
return TrueColor!;
}
return FalseColor!;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
With this I could use AppThemeBinding
when I create the converter:
<ContentPage.Resources>
<converts:BoolToColorConverter
x:Key="ColorConverter"
TrueColor="{AppThemeBinding Light=DarkRed, Dark=LightSalmon}"
FalseColor="#888" />
</ContentPage.Resources>
<VerticalStackLayout>
<Label
Text="Hello, World!"
TextColor="{Binding Source={x:Reference Checky}, Path=IsChecked, Converter={StaticResource ColorConverter}}"
FontSize="32"
HorizontalOptions="Center" />
<CheckBox x:Name="Checky" />
</VerticalStackLayout>
This works as expected if the theme is set on start up.
Dark on start:
Ligh on start:
But if the theme is changed when the application is running, the binding is not reevaluated and the old color is shown. Here is how looks like if thmese is changed from dark mode to light:
Is there some workaround for this?
You could use the Visual State Manager instead.
This is the easiest solution for this specific scenario. Add this converter:
internal class InvertedBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
return !(bool)value;
}
catch
{
return false;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And then use this XAML:
<ContentPage.Resources>
<converts:InvertedBoolConverter x:Key="InvertedBoolConverter" />
</ContentPage.Resources>
<VerticalStackLayout
x:Name="MainLayout"
Spacing="25"
Padding="30,0">
<Label
Text="Hello, World!"
FontSize="32"
HorizontalOptions="Center">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="Checked state">
<VisualState Name="Checked">
<VisualState.StateTriggers>
<StateTrigger
IsActive="{Binding Source={x:Reference Checky}, Path=IsChecked}"
/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light=DarkRed, Dark=LightSalmon}" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Not checked">
<VisualState.StateTriggers>
<StateTrigger
IsActive="{Binding Source={x:Reference Checky}, Path=IsChecked, Converter={StaticResource InvertedBoolConverter}}"
/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="TextColor" Value="#888" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Label>
<CheckBox x:Name="Checky" />
</VerticalStackLayout>
In a more complex scenario, you might want to use a customer trigger instead. Sample:
public class BoolTrigger : StateTriggerBase
{
public static readonly BindableProperty
ValueProperty = BindableProperty.Create(nameof(Value), typeof(object), typeof(BoolTrigger), null, propertyChanged: OnBindablePropertyChanged);
public object Value
{
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public bool OnValue { get; set; }
private static void OnBindablePropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var trigger = bindable as BoolTrigger;
trigger.UpdateTrigger();
}
private void UpdateTrigger()
{
if (Value is not bool val)
{
return;
}
SetActive(OnValue == val);
}
}
And then like this in XAML:
<VerticalStackLayout
x:Name="MainLayout"
Spacing="25"
Padding="30,0">
<Label
Text="Hello, World!"
FontSize="32"
HorizontalOptions="Center">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="Checked state">
<VisualState Name="Checked">
<VisualState.StateTriggers>
<converts:BoolTrigger
OnValue="true"
Value="{Binding Source={x:Reference Checky}, Path=IsChecked}"
/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light=DarkRed, Dark=LightSalmon}" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Not checked">
<VisualState.StateTriggers>
<converts:BoolTrigger
OnValue="false"
Value="{Binding Source={x:Reference Checky}, Path=IsChecked}"
/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="TextColor" Value="#888" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Label>
<CheckBox x:Name="Checky" />
</VerticalStackLayout>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With