4

I need to add an empty item in a bounded combobox within wpf mvvm application, I tried this

<ComboBox TabIndex="23"  Text="{Binding Specialisation}" DisplayMemberPath="refsp_libelle">
      <ComboBox.ItemsSource>
                          <CompositeCollection >
                                        <ComboBoxItem  > </ComboBoxItem>
                                        <CollectionContainer  Collection="{Binding SpecialisationItemSource}" ></CollectionContainer>
                       </CompositeCollection>

     </ComboBox.ItemsSource>
  </ComboBox>

It worked before I tried to add the empty item.

<ComboBox TabIndex="23" Text="{Binding Specialisation}" ItemsSource="{Binding SpecialisationItemSource}" DisplayMemberPath="refsp_libelle"/>

So I need to know :

  1. What is The error that I made?
  2. How can I fix it?

thanks,

Lamloumi Afif
  • 8,941
  • 26
  • 98
  • 191
  • MVVM: Model provides a list (`List`), ViewModel adds blank item to it (`List` + `default()` -> `ObservableCollection`) which is then appears in the View (normal binding). [`CompositeCollection`](https://msdn.microsoft.com/en-us/library/system.windows.data.compositecollection(v=vs.100).aspx) (check sample on msdn) is used to bind static collections into one. Normal bindings is [tricky](http://stackoverflow.com/a/6446923/1997232). – Sinatr Oct 13 '15 at 12:10

1 Answers1

5

Why does your approach not work?

You use {Binding SpecialisationItemSource} which, since no source for the binding is explicitly defined, falls back to using target's DataContext as the source - or rather it would if CollectionContainer was a FrameworkElement, and it's not. Hence the source for the binding is null and no items show up in the combo. You'd need to set the Source property of the binding explicitly to make it work (setting RelativeSource or ElementName wouldn't work either).

Actually even if CollectionContainer was a FrameworkElement it still would not work, because CompositeCollection is not a FrameworkElement (it's not even a DependencyObject ), so the data context inheritance would be broken).

How to fix it?

In order to use the "implicit binding", you can place a CollectionViewSource in a resource dictionary, and use that to fill the collection container by using StaticResource extension:

<ComboBox>
    <ComboBox.Resources>
        <CollectionViewSource x:Key="Items" Source="{Binding SpecialisationItemSource}" />
    </ComboBox.Resources>
    <ComboBox.ItemsSource>
        <CompositeCollection>
            <TextBlock />
            <CollectionContainer Collection="{Binding Source={StaticResource Items}}" />
        </CompositeCollection>
    </ComboBox.ItemsSource>
</ComboBox>

Notice that I used Collection="{Binding Source={StaticResource Items}}" instead of just Collection="{StaticResource Items}" - that's because an object of type CollectionViewSource is not an actual collection and is not valid value for the CollectionContainer.Collection property, and binding mechanism is designed to turn it into an actual collection. Also, I replaced an empty ComboBoxItem with an empty TextBlock, because the former resulted in binding errors, which I really don't like seeing. Ultimately, I'd even go with replacing it with a default value for the bound collection's item type.

Grx70
  • 10,041
  • 1
  • 40
  • 55
  • I don't understand what you mean by "not a Framework element". – Vidar Mar 05 '20 at 11:53
  • @Vidar I mean't it does not derive from [`FrameworkElement` class](https://learn.microsoft.com/en-us/dotnet/api/system.windows.frameworkelement?view=netframework-4.8). – Grx70 Mar 05 '20 at 16:51