Search code examples
wpfdata-bindingwpf-controlscompositecollection

How to use a property of the view model in a CompositeCollection?


When I have a comboBox in my view and want a empty item to be able to unselect the option, I use this code in my view:

<ComboBox.Resources>
    <CollectionViewSource x:Key="comboBoxSource" Source="{Binding ElementName=ucPrincipal, Path=DataContext.MyProperty}" />
</ComboBox.Resources>
<ComboBox.ItemsSource>
    <CompositeCollection>
        <entities:MyType ID="-1"/>
        <CollectionContainer Collection="{Binding Source={StaticResource comboBoxSource}}" />
    </CompositeCollection>
</ComboBox.ItemsSource>

In this case, is the view which sets the ID to -1 to indicate that is special item. But I don't like so much this solution because the view model depends that the view sets it correctly.

So I am thinking to have this property in my view model:

public readonly MyType MyNullItem = new MyType();

But I don't know how to use it in my composite collection in the view instead of:

<entities:MyType ID="-1"/>

Is it possible?

Thanks.


Solution

  • You need some kind of binding converter which would combine one list and one object into CompositeCollection. Some time ago I implemented similar converter with only difference that it converts multiple collections into one:

    /// <summary>
    /// Combines multiple collections into one CompositeCollection. This can be useful when binding to multiple item sources is needed.
    /// </summary>
    internal class MultiItemSourcesConverter : IMultiValueConverter {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
            var result = new CompositeCollection();
    
            foreach (var collection in values.OfType<IEnumerable<dynamic>>()) {
                result.Add(new CollectionContainer { Collection = collection });
            }
            return result;
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
            throw new NotSupportedException();
        }
    }
    

    And usage of such converter looks like this in XAML:

    <ComboBox.ItemsSource>
        <MultiBinding Converter="{StaticResource MultiItemSourcesConverter}">
            <Binding Path="FirstCollection" />
            <Binding Path="SecondCollection" />
        </MultiBinding>
    </ComboBox.ItemsSource>