views:

2607

answers:

2

I have a WPF ComboBox which is databound to a Collection, but depending on wether a Checkbox is checked or not I'd like to vary which Collection the ComboBox is bound to.

The basic issue is I have a large collection of MyCustomer and I also have a filtered collection of MyCustomer - the filtering is quite intensive and I don't want to do it with a CollectionView for the main reason that it is already done, the filtered collection already exists - hence the need to simply switch the databinding of the combo.

I'm hoping for a pure XAML solution, obviously writing some code behind would be a relatively simple solutions but it doesn't feel like it should be required.

A: 

Best way I know is to use some shell collection that internally 'gets' the right collection.

So you have your UnfilteredCollection and your FilteredCollection and then a property called BindingCollection which, in its 'getter,' evaluates some state (the checkbox would be bound to this state) to determine which collection to retrieve.

If you use MVVM for the databinding between the UI and the collections, one way to do it would be like this:

<!-- Your ComboBox binds to some shell collection -->
<ComboBox ItemsSource="{Binding BindingCollection}" />
<!-- The input to this item will determine which collection is internally exposed -->
<CheckBox IsChecked="{Binding UseFilteredSet}" />

And then have your ViewModel (middle-layer) file do something like this (I'm not including the implementation details of INotifyPropertyChanged, but I can if you wish):

private ObservableCollection<MyCustomer> UnfilteredCollection
{
    get { return _unfilteredCollection; }
}

private ObservableCollection<MyCustomer> FilteredCollection
{
    get { return _filteredCollection; }
}

// The public collection to which your ComboBox is bound
public ObservableCollection<MyCustomer> BindingCollection
{
    get 
    { 
        return UseFilteredSet ? 
            FilteredCollection : 
            UnfilteredCollection; 
    }
}

// CheckBox is bound to this state value, which tells the bindings on the shell 
// collection to refresh when the value of this state changes.
public bool UseFilteredSet
{
    get { return _useFilteredSet; }
    set 
    { 
        _useFilteredSet = value;
        OnPropertyChanged("UseFilteredSet");
        OnPropertyChanged("BindingCollection");
    }
}
KP Adrian
Thanks KP - I had this thought yesterday but was hoping for a 'purer' xaml solution - perhaps I'm barking up the wrong tree and a pure xaml solution isn't the correct way to be going about things in the first place.
Scott
Well the only other thing that even comes to mind is some kind of trigger-based approach that changes the 'ItemsSource' property based upon the checkbox's IsChecked property, but I don't know how to get that to work.
KP Adrian
+3  A: 

Here's an example using a DataTrigger to switch the collections:

<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
    <StackPanel.Resources>
        <x:Array x:Key="notes" Type="{x:Type sys:String}">
            <sys:String>do</sys:String>
            <sys:String>re</sys:String>
            <sys:String>mi</sys:String>
        </x:Array>
        <x:Array x:Key="letters" Type="{x:Type sys:Char}">
            <sys:Char>a</sys:Char>
            <sys:Char>b</sys:Char>
            <sys:Char>c</sys:Char>
        </x:Array>
    </StackPanel.Resources>

    <CheckBox x:Name="chkLetters" Content="Use Letters"/>
    <ListBox>
        <ListBox.Style>
            <Style TargetType="{x:Type ListBox}">
                <Setter Property="ItemsSource" Value="{StaticResource notes}"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsChecked, ElementName=chkLetters}" Value="True">
                        <Setter Property="ItemsSource" Value="{StaticResource letters}"/>
                    </DataTrigger>
                 </Style.Triggers>
            </Style>
        </ListBox.Style>
    </ListBox>
</StackPanel>

For you these wouldn't be different arrays, but probably different CollectionViewSources with filters or something, but the principle is the same.

Robert Macnee