EDIT: Oops, I misread, thought you wanted text color change for new items. Updated the below so it will change the item background color if the item is newly added, and will change the text color for a value if it has changed since the last refresh.
You would want to bind the TextColor property for the Label to a boolean value indicating whether the value is changed or not, and you would need to use a ValueConverter to convert the boolean to a color.
Here's a simple example (much of the below code is to simulate adding and updating items in the list, points of interest are the value converters and how to use them to turn a bound bool value into a color):
MainPage.xaml.cs: (includes converters and item view model)
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Timers;
using Xamarin.Forms;
namespace ChangeTextColorForNewItemsInListView
{
// Learn more about making custom code visible in the Xamarin.Forms previewer
// by visiting https://aka.ms/xamarinforms-previewer
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage
{
public ObservableCollection<ItemViewModel> Items { get; set; } = new ObservableCollection<ItemViewModel>();
Timer _timer;
int itemNumber = 0;
Random randomNumber = new Random(DateTime.Now.Millisecond);
public MainPage()
{
InitializeComponent();
BindingContext = this;
}
protected override void OnAppearing()
{
base.OnAppearing();
for (int i = 0; i < 10; i++)
{
Items.Add(new ItemViewModel
{
ValueA = $"ValueA {++itemNumber}",
ValueB = $"ValueB {itemNumber}",
ValueC = $"ValueC {itemNumber}",
IsNew = true
});
}
_timer = new Timer(2000);
_timer.AutoReset = true;
_timer.Elapsed += Timer_Elapsed;
_timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
foreach (var item in Items)
{
item.IsNew = false;
item.ValueA = item.ValueA.Replace(" new", "");
item.ValueB = item.ValueB.Replace(" new", "");
item.ValueC = item.ValueC.Replace(" new", "");
item.ValueAChanged = false;
item.ValueBChanged = false;
item.ValueCChanged = false;
int changeValue = randomNumber.Next(0, 15);
switch (changeValue)
{
case 0:
item.ValueA = item.ValueA.Replace(" new","") + " new";
break;
case 1:
item.ValueB = item.ValueB.Replace(" new", "") + " new";
break;
case 2:
item.ValueC = item.ValueC.Replace(" new", "") + " new";
break;
default:
break;
}
}
for (int i = 0; i < randomNumber.Next(1,5); i++)
{
Items.Insert(randomNumber.Next(1, Items.Count -1) ,new ItemViewModel
{
ValueA = $"ValueA {++itemNumber}",
ValueB = $"ValueB {itemNumber}",
ValueC = $"ValueC {itemNumber}",
IsNew = true
});
}
}
}
public class ItemViewModel : INotifyPropertyChanged
{
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
bool _isNew;
public bool IsNew
{
get => _isNew;
set
{
if (_isNew != value)
{
_isNew = value;
OnPropertyChanged();
}
}
}
bool _valueAChanged;
public bool ValueAChanged
{
get => _valueAChanged;
set
{
if (_valueAChanged != value)
{
_valueAChanged = value;
OnPropertyChanged();
}
}
}
string _valueA;
public string ValueA
{
get => _valueA;
set
{
if (_valueA != value)
{
_valueA = value;
ValueAChanged = true;
OnPropertyChanged();
}
}
}
bool _valueBChanged;
public bool ValueBChanged
{
get => _valueBChanged;
set
{
if (_valueBChanged != value)
{
_valueBChanged = value;
OnPropertyChanged();
}
}
}
string _valueB;
public string ValueB
{
get => _valueB;
set
{
if (_valueB != value)
{
_valueB = value;
ValueBChanged = true;
OnPropertyChanged();
}
}
}
bool _valueCChanged;
public bool ValueCChanged
{
get => _valueCChanged;
set
{
if (_valueCChanged != value)
{
_valueCChanged = value;
OnPropertyChanged();
}
}
}
string _valueC;
public string ValueC
{
get => _valueC;
set
{
if (_valueC != value)
{
_valueC = value;
ValueCChanged = true;
OnPropertyChanged();
}
}
}
}
public class BoolToColorConverterNewItem : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? Color.Yellow : Color.White;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException("No need to convert from color to bool");
}
}
public class BoolToColorConverterChangedValue : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? Color.Red : Color.Black;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException("No need to convert from color to bool");
}
}
}
MainPage.xaml:
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="using:ChangeTextColorForNewItemsInListView"
mc:Ignorable="d"
x:Class="ChangeTextColorForNewItemsInListView.MainPage"
>
<ContentPage.Resources>
<ResourceDictionary>
<local:BoolToColorConverterChangedValue x:Key="boolToColorCV" />
<local:BoolToColorConverterNewItem x:Key="boolToColorNI" />
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Margin="0,50,0,0">
<!-- Place new controls here -->
<ListView HasUnevenRows="True" ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="{Binding IsNew, Converter={StaticResource boolToColorNI}}">
<Label
Grid.Column="0"
Text="{Binding ValueA}"
TextColor="{Binding ValueAChanged, Converter={StaticResource boolToColorCV}}" />
<Label
Grid.Column="1"
Text="{Binding ValueB}"
TextColor="{Binding ValueBChanged, Converter={StaticResource boolToColorCV}}" />
<Label
Grid.Column="2"
Text="{Binding ValueC}"
TextColor="{Binding ValueCChanged, Converter={StaticResource boolToColorCV}}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>