Reputation: 112
I am developing a Xamarin app which I am testing on an Android device. I have a XAML view and I am binding an enum property in the viewmodel to multiple controls - one for text value, and the other to background color with an IValueConverter. Relevant XAML code:
<ContentView
BackgroundColor="{Binding MyField, Converter={StaticResource MyFieldEnumValueToColorConverter}}"
>
<ContentView.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding MyFieldClickCommand}" />
</ContentView.GestureRecognizers>
<Label
Text="{Binding MyField}"
/>
</ContentView>
IValueConverter implementation:
public class MyFieldEnumValueToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is MyFieldEnum)
{
switch ((MyFieldEnum)value)
{
case MyFieldEnum.Value1:
return Color.Orange;
case MyFieldEnum.Value2:
return Color.Green;
case MyFieldEnum.Value3:
return Color.Red;
}
}
return Color.White;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Property in the viewmodel (yes, it does implement INotifyPropertyChanged):
public event PropertyChangedEventHandler PropertyChanged;
private MyFieldEnum _myField;
public MyFieldEnum MyField
{
get => _myField;
set
{
_myField= value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MyField)));
}
}
When I load this page, the controls load properly for every distinct enum value: the text and the background color both reflect the actual value.
In a click handler, I simply set the property value like this:
MyField = MyFieldEnum.Value2;
The text changes, but the background color does not. Why?
I also tried introducing a new field (of type Color), implement the IValueConverter logic directly in the getter, and bind that to the BackgroundColor attribute of the ContentView. Same issue. The page has many other data-bound items and all work properly except this one.
UPDATE: it appears that the problem is with the ContentView. I put the exact same BackgroundColor binding to the Label itself and there it works as expected, but for the ContentView it does not.
Upvotes: 0
Views: 95
Reputation: 112
So I found the underlying cause.
The ContentView also has a style defined in a StaticResource which adds a few styling rules to the control (background color included). I conveniently omitted this style from my question for brevity. I figured this might be an issue so I removed the background color from the style, but the problem persisted. I fiddled with XAML attribute order as I remember that it gave me a hard time before, but no luck there either.
I looked closer at the defined styles and I found that the style includes a Xamarin.Forms RoutingEffect for a rounded corner with a configurable radius. Upon examining the Android-specific implementation of the code I realized that it achieves the corner radius it sets the background color to transparent and sets the container layer's background color to the original background color and the corner radius. It is my understanding that this piece of code runs once when the element is rendered (OnAttached). The initially bound background color is correct because it is applied before, but it is overridden and I believe that the binding is overridden/removed when the effect sets the view's background color to transparent.
I confirmed this being the root cause by removing the effect from the element, and it started working as expected. Of course, I lost the rounded corners for this element, which makes the UI inconsistend, but that is a problem for another day. Thanks for everyone for the suggestions!
Upvotes: 1