Reputation: 13256
I'm trying to change the colour of a button when a property in the datasource changes. Initialising the background colour works correctly based on the initial value of the IsFilterOn
property but it isn't updating when the property changes.
The XAML
<FlexLayout BindableLayout.ItemsSource="{Binding Filters}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Button>
<Button.Triggers>
<DataTrigger Binding="{Binding IsFilterOn}" TargetType="Button" Value="False">
<Setter Property="BackgroundColor" Value="{Binding UpColour}" />
</DataTrigger>
<DataTrigger Binding="{Binding IsFilterOn}" TargetType="Button" Value="True">
<Setter Property="BackgroundColor" Value="{Binding DownColour}" />
</DataTrigger>
</Button.Triggers>
</Button>
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
Filters
is an ObservableCollection<FilterModel>
:
public class FilterModel
{
public string UpColour { get; set; }
public string DownColour { get; set; }
public bool IsFilterOn { get; set; }
}
Tapping a button correctly updates the IsFilterOn
property for the button (code not shown) but the UI doesn't change to reflect it. What am I doing wrong?
Upvotes: 1
Views: 1407
Reputation: 11105
We cannot see how you are updating the IsFilterOn
property from true
to false
but if you are directly changing the property of one of the FilterModel
instances in the list, then the property changed event will not be invoked.
The ObservableCollection
will execute property changed events when you add or remove something from the list, but it is not watching objects' properties.
You have 2 options, either invoke Property Changed events from your FilterModel
anytime IsFilterOn
is updated or change all of the property values you need to and then manually execute property changed on the list. If you are updating multiple FilterModel
s at the same time, performance would probably be better with the second option.
Option 1:
public class FilterModel : INotifyPropertyChanged {
public string UpColour { get; set; }
public string DownColour { get; set; }
private bool _isFilterOn = false;
public bool IsFilterOn {
get { return _isFilterOn; }
set {
_isFilterOn = value;
NotifyPropertyChanged(); // Anytime this property is changed Property Changed will be executed
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Option 2:
public class FilterViewModel {
private ObservableCollection<FilterModel> _filters;
public ObservableCollection<FilterModel> Filters {
get => _filters ?? (_filters = new ObservableCollection<FilterModel>());
set {
_filters = value;
NotifyPropertyChanged();
}
}
public void ToggleFilters() {
// some logic
Filters[0].IsFilterOn = true; // Make all property changes
NotifyPropertyChanged(nameof(Filters)); // Tell the UI that the list has been updated and to refresh the data
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Upvotes: 1