Home > Software design >  Why IMultiValueConverter doesn't get updated ObservableCollection as a parameter?
Why IMultiValueConverter doesn't get updated ObservableCollection as a parameter?

Time:03-26

I have an ItemsControl that was set like this:

<ItemsControl ItemsSource="{Binding GameObjects}" 
                          AlternationCount="{Binding GameObjects.Count}" 
                          Grid.RowSpan="10"
                          Grid.ColumnSpan="10">
<DataTemplate>
    <Grid>
        <Grid.DataContext>
            <vm:MainWindowViewModel/>
        </Grid.DataContext>
        <TextBlock Text="{Binding Path=(ItemsControl.AlternationIndex), 
                         RelativeSource={RelativeSource TemplatedParent}}"/>
        <Image>
            <Image.Source>
                <MultiBinding Converter="{StaticResource 
                    ObservableCollectionItemByAlternationIndex}">
                    <Binding Path="Textures"/>
                    <Binding Path="GameObjects"/>
                    <Binding Path="(ItemsControl.AlternationIndex)"
                        RelativeSource="{RelativeSource TemplatedParent}"/>
                </MultiBinding>
            </Image.Source>
        </Image>
    </Grid>
</DataTemplate>

The converter looks like this:

public override object Convert(object[] v, Type t, object p, CultureInfo c)
    {
        var value1 = (ObservableCollection<string>)v[0];
        var value2 = (ObservableCollection<GameObject>)v[1];
        var value3 = (int)v[2];

        foreach(var tex in value1)
        {
            if ("/Maelstrom;component//Data/Resources/Textures/"   value2[value3].GetType().Name   ".png" == tex)
            {
                return new BitmapImage(new Uri("pack://application:,,,"   tex));
            }
        }

        return new BitmapImage(new Uri("pack://application:,,,"   value1[0]));
    }

The issue here is that when I update GameObjects, converter doesn't gets updated version of GameObjects, instead of it, value1 will contain all elements that were inside GameObjects when program started. ItemsControl updates normally (items that were removed from GameObjects also were removed from the UI).

CodePudding user response:

The problem is that you are are confusing INotifyPropertyChanged with INotifyCollectionChanged.

A multi-binding is only updated if one of the properties in one of the bindings issues an INotifyPropertyChanged.PropertyChanged event. In other words, if the entire collection underlying Textures or GameObjects was completely replaced with a brand new instance of ObservableCollection

But that's not what happens when you add/remove items to/from an ObservableCollection. In that case, the property that returns that collection object does not change at all; The very same ObservableCollection object remains. But the collection itself raises the INotifyCollectionChanged.CollectionChanged event.

The only way that WPF can react to this is if some object is monitoring that specific ObservableCollection object for INotifyCollectionChanged. And that cannot possibly happen when you use it in a MultiBinding because the ObservableCollection gets lost in the conversion. The MultiBinding returns one single value and whatever that value is, it's not any object that implements INotifyCollectionChanged.

You might want instead to look into the CompositeCollection class. That might be a better approach

  • Related