Al John
Al John

Reputation: 900

ObservableCollection conditional color binding in .NET MAUI

Using Binding with an ObservableCollection in .NET MAUI, how do I conditionally set the BackgroundColor property of a GUI element and evaluate the conditions for each item individually?

XAML <Label BackgroundColor="{Binding name.color}"/>
C# if (x) { name.color = Colors.Red; } else { name.color = Colors.Blue; }
or using string data like this:
C# name.color = "#FF0000"; does not work.

C# LabelCommonName.BackgroundColor = Colors.Red;
impossible using a CollectionView.

My actual XAML
I've left out the margins, paddings, grid definitions and other irrelevant styling.

<?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"
             xmlns:local="clr-namespace:projectName"
             x:Class="projectName.CalendarPage"
             Title="CalendarPage">
    <Grid>
        <ScrollView>
            <RefreshView x:Name="CalendarRefresh"
                         Refreshing="RefreshCalendar">
                <CollectionView x:Name="CalendarView">
                    <CollectionView.ItemTemplate>
                        <DataTemplate x:DataType="local:Calendar">
                            <Frame>
                                <Grid>
                                    <!-- Trying to evaluate this BackgroundColor for each item in the CollectionView individually, so not the same value for all items: -->
                                    <Label BackgroundColor="{Binding 
                                               if (name.color=1) {
                                                   Colors.Red
                                               } else if (name.color=2) {
                                                   Colors.Blue
                                               } else {
                                                   Colors.Green
                                               }
                                           }" 
                                           x:Name="LabelCommonName" 
                                           Text="{Binding name.common}"/>
                                    <Label Text="{Binding name.scientific}"/>
                                </Grid>
                            </Frame>
                        </DataTemplate>
                    </CollectionView.ItemTemplate>
                </CollectionView>
            </RefreshView>
        </ScrollView>
    </Grid>
</ContentPage>

My code behind
Using an ObservableCollection to add more items when scrolling down.

public partial class CalendarPage : ContentPage
{
    private ActivityIndicator activityIndicator = new ActivityIndicator() { IsRunning = false };
    private ObservableCollection<Calendar> calendars = new ObservableCollection<Calendar>();
    private string url = "[censored]";
    private int start = 0;
    private int limit = 10;

    public CalendarPage()
    {
        InitializeComponent();
        LoadCalendar();
    }

    private void RefreshCalendar(object sender, EventArgs e)
    {
        LoadCalendar();
        CalendarRefresh.IsRefreshing = false;
    }

    private void ScrollCalendar(object sender, ItemsViewScrolledEventArgs e)
    {
        if (e.LastVisibleItemIndex > (start - limit))
        {
            LoadCalendar();
        }
    }

    private async void LoadCalendar()
    {
        if (activityIndicator.IsRunning == true)
        {
            return;
        }
        else
        {
            activityIndicator.IsRunning = true;

            var http = new HttpClient();
            var items = await http.GetFromJsonAsync<List<Calendar>>(url + start + limit);

            foreach (var item in items)
            {
                calendars.Add(item);
            }

            CalendarView.ItemsSource = calendars;

            activityIndicator.IsRunning = false;

            start += limit;
        }
    }
}

Calendar class
Items are collected through an API externally so there's an item template.

namespace projectName;

public class Calendar
{
    public int item_id { get; set; }
    public int status { get; set; }
    public Name name { get; set; }
}

public class Name
{
    public string common { get; set; }
    public string scientific { get; set; }
    public string color { get; set; }
}

Upvotes: 1

Views: 1903

Answers (1)

Liqun Shen-MSFT
Liqun Shen-MSFT

Reputation: 8220

You may use a Binding value converters.

You could define a ColorChangedConverter which inherit IValueConverter:

public class ColorChangedConverter : IValueConverter
{
    public ColorChangedConverter()
    {
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {

        if ((int)value == 1)
        {
            return Colors.Red;
        }
        else if ((int)value == 2)
        {
            return Colors.Blue;
        }
        else
        {
            return Colors.Green;
        }                  
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

And in xaml consume Converters:

<ContentPage.Resources>
    <local:ColorChangedConverter x:Key="colorChangedConverter" />
</ContentPage.Resources>


<Grid>
    <ScrollView>
        <RefreshView x:Name="CalendarRefresh"                       >
            <CollectionView x:Name="CalendarView">
                <CollectionView.ItemTemplate>
                    <DataTemplate x:DataType="local:Calendar">
                        <Frame x:Name="myframe">
                            <StackLayout>
                                <Label x:Name="LabelCommonName"
                                       Text="{Binding name.common}" BackgroundColor="{Binding name.color,Converter={StaticResource colorChangedConverter}}">
                                </Label>
                                <Label Text="{Binding name.scientific}"
                                       TextColor="{Binding name.color}"/>
                                <Label x:Name="mylabel" Text="{Binding item_id}"/>
                            </StackLayout>
                        </Frame>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </RefreshView>
    </ScrollView>
</Grid>

In code behind, I add some test code:

private ObservableCollection<Calendar> calendars = new ObservableCollection<Calendar>();
public MainPage()
{
    InitializeComponent();
    LoadCalendar();
}

private async void LoadCalendar()
{

    calendars.Add(new Calendar
    {
        item_id = 1,
        status = 1,
        name = new Name
        {
            common = "common1",
            scientific = "scientific1",
            color = 1
        }
    });
    calendars.Add(new Calendar
    {
        item_id = 2,
        status = 2,
        name = new Name
        {
            common = "common2",
            scientific = "scientific2",
            color = 2
        }
    });

    calendars.Add(new Calendar
    {
        item_id = 3,
        status = 3,
        name = new Name
        {
            common = "common3",
            scientific = "scientific3",
            color = 3
        }
    });

    CalendarView.ItemsSource = calendars;
}

The following image shows the result:

enter image description here

Hope it works.

Upvotes: 3

Related Questions