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