Arturo Calvo
Arturo Calvo

Reputation: 58

Color converter binding not being called

I have a label with black text color inside a frame with white background color, the thing is, I want to assign the background color and text color from the viewmodel, I have created the converter, and did the bindings, but for some reason it isn't working

this is my view code:

?xml version="1.0" encoding="UTF-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="ComanderoMovil.Views.PlatillosView"
    xmlns:ios="clr -namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
    ios:Page.UseSafeArea="true"
    xmlns:behaviorsPack="clr- namespace:Xamarin.Forms.BehaviorsPack;assembly=Xamarin.Forms.Behaviors Pack"
    xmlns:converterPack="clr-namespace:ComanderoMovil.Converters">

    <ContentPage.Resources>
        <ResourceDictionary>
            <converterPack:ColorConverter x:Key="ColorConverter"/>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.Content>
        <StackLayout>
            <SearchBar> </SearchBar>
            <CollectionView ItemsSource="{Binding Grupos}"
                            HeightRequest="50"
                            ItemsLayout="HorizontalList"
                            SelectionMode="Single"
                            SelectionChangedCommand="{Binding 
SelectedGrupoCommand, Mode=TwoWay}">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <ContentView Padding="2">
                            <Frame BorderColor="Black"
                                   HasShadow="False"
                                   Padding="2"
                                   BackgroundColor="{Binding 
ButtonBackColor, Converter={StaticResource ColorConverter}}">
                                <StackLayout>
                                    <Label Margin="10"
                                           Text="{Binding nombre}"
                                           TextColor="{Binding 
TextColor, Converter = {StaticResource ColorConverter}}"

VerticalTextAlignment="Center"

 HorizontalTextAlignment="Center"
                                           FontSize="Small"

VerticalOptions="CenterAndExpand"></Label>
                                </StackLayout>
                            </Frame>
                         </ContentView>
                     </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
 </ContentPage.Content>
</ContentPage>

Here is my ViewModel:

public class PlatillosViewModel : INotifyPropertyChanged
{
    private INavigation Navigation;
    private ObservableCollection<PlatilloModel> _platillos;
    private string _textColor;
    private string _backColor;
    public event PropertyChangedEventHandler PropertyChanged;
    public ObservableCollection<GrupoModel> Grupos { get; set; }
    public ObservableCollection<PlatilloModel> Platillos
    {
        get => _platillos;
        set
        {
            _platillos = value;
            OnPropertyChanged();
        }
    }

    public string TextColor
    {
        get => _textColor;
        set
        {
            _textColor = value;
            OnPropertyChanged();
        }
    }

    public string ButtonBackColor
    {
        get => _backColor;
        set
        {
            _backColor = value;
            OnPropertyChanged();
        }
    }

    public PlatillosViewModel(INavigation navigation)
    {
        Navigation = navigation;
        TextColor = "Black";
        ButtonBackColor = "White";
        PlatillosRepository repository = new PlatillosRepository();
        Platillos = repository.GetAll();
        GrupoRepository grupoRepository = new GrupoRepository();
        Grupos = grupoRepository.GetAll();
    }

    public ICommand SelectedPlatilloCommand => new Command<PlatilloModel>(async platillo =>
    {
        await Navigation.PushAsync(new PlatilloView());
    });

    public ICommand SelectedGrupoCommand => new Command<GrupoModel>(async grupo =>
    {
        ButtonBackColor = "Black";
        TextColor = "White";
        PlatillosRepository platillosRepository = new PlatillosRepository();
        Platillos = platillosRepository.GetFilteredByGroup(grupo);
    });

    protected virtual void OnPropertyChanged([CallerMemberName] string property = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }
}

and Here is my converter:

public class ColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var valor = value.ToString();
        switch(valor)
        {
            case "White":
                return Color.White;
            case "Black":
                return Color.Black;
            default:
                return Color.Red;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

Upvotes: 2

Views: 1333

Answers (1)

pinedax
pinedax

Reputation: 9356

Your issue is not with the ValueConverter but with your Bindings.

<CollectionView ItemsSource="{Binding Grupos}"
                HeightRequest="50"
                ItemsLayout="HorizontalList"
                SelectionMode="Single"
                SelectionChangedCommand="{Binding SelectedGrupoCommand, Mode=TwoWay}">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <ContentView Padding="2">
                <Frame BorderColor="Black"
                        HasShadow="False"
                        Padding="2"
                        BackgroundColor="{Binding ButtonBackColor, Converter={StaticResource ColorConverter}}">
                    <StackLayout>
                        <Label Margin="10"
                                Text="{Binding nombre}"
                                TextColor="{Binding TextColor, Converter = {StaticResource ColorConverter}}"
                                VerticalTextAlignment="Center"
                                HorizontalTextAlignment="Center"
                                FontSize="Small"
                                VerticalOptions="CenterAndExpand">
                        </Label>
                    </StackLayout>
                </Frame>
                </ContentView>
            </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

You are using a CollectionView and when you set the ItemSource

<CollectionView ItemsSource="{Binding Grupos}"

All the bindings you do inside will assume this as the BindingContext.

<Label Margin="10"
        Text="{Binding nombre}"
        TextColor="{Binding TextColor, Converter = {StaticResource ColorConverter}}"
        VerticalTextAlignment="Center"
        HorizontalTextAlignment="Center"
        FontSize="Small"
        VerticalOptions="CenterAndExpand" />

The same way the nombre property you are binding to the Label Text Property, is part of the GroupModel class, that way the TextColor and ButtonBackColor properties are expected to be part of the same class you did bind as the ItemSource.

If you want to make it work: either add these two properties (TextColor and ButtonBackColor) to the GroupModel class or change the binding so that these two properties are accessed from the parent Binding.

The first one will give you more flexibility but at the same time might add repeated code (if all the items will share the same color for example).

The second option can be accomplished this way:

Add a name to the CollectionView

<CollectionView ItemsSource="{Binding Grupos}"
                HeightRequest="50"
                x:Name="GruposList"
               ....

Then we are gonna change a bit the binding of those items that are not part of your GrupoModel but are part of the ViewModel

<DataTemplate>
    <ContentView Padding="2">
        <Frame BorderColor="Black"
                HasShadow="False"
                Padding="2"
                BackgroundColor="{Binding BindingContext.ButtonBackColor, 
                                  Source={x:Reference GruposList}, 
                                  Converter={StaticResource ColorConverter}}">
            <StackLayout>
                <Label Margin="10"
                        Text="{Binding nombre}"
                        TextColor="{Binding BindingContext.TextColor, 
                                    Source={x:Reference GruposList}, 
                                    Converter={StaticResource ColorConverter}}"
                        VerticalTextAlignment="Center"
                        HorizontalTextAlignment="Center"
                        FontSize="Small"
                        VerticalOptions="CenterAndExpand">
                </Label>
            </StackLayout>
        </Frame>
    </ContentView>
</DataTemplate>

As you can see we are now accessing them through the CollectionView Binding, we do this when we specify the Source and use a Reference. More about bindings here

Hope this helps.-

Side Note:

In your converter watch for nulls.

var valor = value.ToString();

The above can make your application crash if value is null.

Use this instead:

var valor = value?.ToString();

Upvotes: 2

Related Questions