mauiobservablecollection

MAUI ObservableCollection not triggering Converter


I have an ObservableCollection of strings:

public ObservableCollection<string> ChallengePartImageURLs { get; } = new ObservableCollection<string>();

Being populated/updated like this:

ChallengePartImageURLs.Clear();
foreach(var url in SelectedChallengePart.ImageURLs) {
    ChallengePartImageURLs.Add(url);
}

The UI is updated just fine, however, the converter is not triggered when the collection is changing:

IsVisible="{Binding ChallengePartImageURLs, Converter={StaticResource AnyImageCheckConverter}}"

The converter is working because if I change the ObservableCollection to an ObservableProperty it is perfectly triggered.

I have tried including a Binding to a ConverterParameter of an ObservableProperty but it is still not triggered.

Am I missing something or is there a way to trigger the converter?

Update

The converter is declared in XAML:

<ContentPage.Resources>
        <ResourceDictionary>
            <converters:AnyImageCheckConverter x:Key="AnyImageCheckConverter"/>
        </ResourceDictionary>
</ContentPage.Resources>

Used:

<CollectionView ItemsSource="{Binding ChallengePartImageURLs}" IsVisible="{Binding ChallengePartImageURLs, Converter={StaticResource AnyImageCheckConverter}}">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Label Text="{Binding .}" />
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

The converter itself:

{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            if (value != null)
            {
                var list = (ObservableCollection<string>)value;
                if (list.Count > 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            return false;
        }
        catch (Exception ex)
        {
        }
        return false;
    }

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

The Collection is only changed by clearing it and adding new items.


Solution

  • The main reason that the converter is not triggered, as you discovered, is that the Converter will only be run after a PropertyChangedEvent. The ObservableCollection when items are cleared, added, or removed emit NotifyCollectionChangedAction.

    What that means practically for your use case is to trigger a property changed event so that the converter will be run after you update the collection. The nice part about the way this behaves is that your page will not run the converter each time something is added or removed from you collection.

    ChallengePartImageURLs.Clear();
    foreach(var url in SelectedChallengePart.ImageURLs) {
      ChallengePartImageURLs.Add(url);
    }
    PropertyChanged(this, new PropertyChangedEventArgs(nameof(ChallengePartImageURLs)));
    

    Or if you are using MVVM toolkit, you can simplify the propteryChanged call

    ChallengePartImageURLs.Clear();
    foreach(var url in SelectedChallengePart.ImageURLs) {
      ChallengePartImageURLs.Add(url);
    }
    OnPropertyChanged(nameof(ChallengePartImageURLs));
    

    I hope you find this helpful. I have had to implement this kind of behavior numerous times in my app. I found extending ObservableCollection to add this behavior quite beneficial.