Hello, I am having a little issue using List View in Xamarin Forms.
I have populated my ListView using the MVVM Architecture. The codes are as follows
What I want to achieve is to have my TextColor Attribute turn Red for one of my Label in the textview.. How can I achieve this correctly ?
**My XAML Page : **
<ListView.ItemTemplate> <DataTemplate> <ViewCell> <Grid Padding="12"> <Label Text="{Binding UID}" TextColor="Black" FontSize="12"/> <Label Text="{Binding battery}" TextColor="{Binding StatusColor}" FontSize="12" XAlign="End"/> </Grid> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
**My TagsViewModel.cs (MVVM) : **
public class TagsViewModel : INotifyPropertyChanged
{
private List _tagsModel;
public List<Tags> TagsModel { get { return _tagsModel; } set { _tagsModel = value; OnPropertyChanged(); } } private string _statusColor; public string StatusColor { get { return _statusColor; } set { _statusColor = value; OnPropertyChanged(); } } public TagsViewModel() { TagsModel = new List<Tags>(); TagsModel.Add(new Tags() { id = 1, UID = "324324", UIDid = 4324325, battery = "14/02/2017" }); TagsModel.Add(new Tags() { id = 2, UID = "258225", UIDid = 4324325, battery = "15/02/2017" }); TagsModel.Add(new Tags() { id = 3, UID = "854224", UIDid = 4324325, battery = "16/02/2017" }); TagsModel.Add(new Tags() { id = 4, UID = "582253", UIDid = 4324325, battery = "14/02/2017" }); TagsModel.Add(new Tags() { id = 5, UID = "253245", UIDid = 4324325, battery = "17/02/2017" }); StatusColor = "Red"; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
Noticed an error which @AlessandroCaliaro correctly spotted, I missed his post
<Label Text="{Binding battery}" TextColor="{Binding UID, Converter={converters:StartsWithToColorConverter }}" FontSize="12" XAlign="End"/>
I'm pretty busy so trying to answer you and write some code at the same time don't do multi-tasking
Answers
StatusColor property should be of type "Color", not a string.
But when used in the BindingContext, it can be treated as a string also.. I have test the Binding outside the listview in a label and it works. The problem arises when I bind it in the listview.
@HamsheedSalamut
Best way would be a data trigger or a value converter rather than setting presentation logic in the viewmodel
https://blog.xamarin.com/triggers-in-xamarin-forms/
I want to set the TextColor to Red of each UID that starts with the digit '3'. How can I achieve this ?
The best way (my point of view) is to use datatriggers like this:
The color value should not be in the class (it's not MVVM), the designer must bind the codestatus and choose color.
https://forums.xamarin.com/discussion/comment/60076/#Comment_60076
IValueConverter
@HamsheedSalamut
Then in your marksup
Just add the converter namespace in the xaml namespaces
@NMackay
I think you should verify value before use it
But I think you should return a Color, not a string...
Or you can use IMarkupExtensions too
But i prefer DataTriggers 
TextColor = "{Binding UID....
@AlessandroCaliaro
I did test and it works fine, your spot on about the null check, I have changed the sample
"The color value should not be in the class (it's not MVVM), the designer must bind the codestatus and choose color."
What do you mean by this ? Where the Value property should be specified if not in the MVVM >
I think if he used Markup he should bind the CodeStatus, not the statusColor and the markup return the color
@TonyPinot
I just implemented IMarkupExtension so you don't have to add the converter as resource, makes it easier to get the converter working which can be tricky if it's your 1st time, small cost of IServiceProvider I guess.
Can you provide the namespace as well ?
@HamsheedSalamut
It's where the converter lives in your assembly
xmlns:converters="clr-namespace:MyAppName.Converters;assembly=MyAppName"
MVVM concept is split the design and the data and if you add the color (design value) in the model class you didn't respect this (my point of view in this situation).
Now, you got a StatusColor right? So you must have a CodeStatut right? So bind the codestatus and edit color in XAML by datatriggers or markup
I'm a newbie in MVVM but i think we should works like this
If you are in the same solution you just can write here:
Tips:
@TonyPinot
I think your trigger solution is the nicest, I don't think the vanilla triggers can handle conditions such as starts with (please correct me if I'm wrong).
I use the awesome little library that will handle this scenario purely in XAML.
http://www.davidbritch.com/2016/04/xamarinforms-behaviors_13.html
https://www.nuget.org/packages/Behaviors.Forms/
edit:
tell a lie, it doesn't support starts with.
@NMackay
I don't know, i'm a newbie i need to learn more with XAML, but i think datatriggers is the most natural writing.
For example, i never try to use behaviors or effect, but i will
@TonyPinot
Everyday is a school day working with Xamarin and Xamarin Forms
The CodeStatus, where do I need to set it ? Should I define a property in the MVVM class ? or define it a model? I don't understand this part Value="1"
@HamsheedSalamut
Does the value converter approach work?
Nope. Its not working
@HamsheedSalamut
Noticed an error which @AlessandroCaliaro correctly spotted, I missed his post
<Label Text="{Binding battery}" TextColor="{Binding UID, Converter={converters:StartsWithToColorConverter }}" FontSize="12" XAlign="End"/>
I'm pretty busy so trying to answer you and write some code at the same time
don't do multi-tasking
Thanks ! It works like charm _
Thank you very much
@HamsheedSalamut
Your welcome.
I would like to certainly try your solution and make it work. Please help me to proceed
I will always remain a donkey
@HamsheedSalamut
I'm not sure you can get round your scenario using startswith without using a value converter somewhere, the library I mentioned allows more powerful comparisons for triggers but it doesn't support startswith. If your trigger is based on a boolean you'd have to do something like the following (I don't know if this would work)
<Label Text="{Binding battery}" FontSize="12" XAlign="End"> <Label.Triggers> <DataTrigger TargetType="Label" Binding="{Binding UID, Converter={converters:StartsWithToBoolConverter }}" Value="0"> <Setter Property="TextColor" Value="Black"/> <!-- You can add more properties here --> </DataTrigger> <DataTrigger TargetType="Label" Binding="{Binding UID, Converter={converters:StartsWithToBoolConverter }}" Value="1"> <Setter Property="TextColor" Value="Red"/> <!-- You can add more properties here --> </DataTrigger> <!-- You can add more datatrigger here --> </Label.Triggers> </label>
Converter
I haven't tested but maybe worth trying if you have spare time.
It's easier, Value="" match with the _value _of Binding=""
For example
@TonyPinot
So how do you handle the startsWith scenario?
@NMackay
Code:
In XAML:
And if your status never change so it's not a statut?, you should use StaticResource or DynamicResource?
@TonyPinot
I see what your doing but I think id is just a sequence and wouldn't work in his scenario (any UID starting with 3 turns red), I totally agree though, if it's lookup values etc your approach would be the best.
Like this?
Code
XAML
Wouldn't that just make every label red?
@NMackay @HamsheedSalamut
Okay my bad i didn't read the 3 digits conditions ! I was writing my first answer when he add this condition
So MarkupExtension is the best way if you have only one property to change (like TextColor) but if you want edit more i think you should add in your class Tag a property with the first digit and use datatriggers after
Or, a MarkupExtension can return a XAML Style?