开发者

Multiple ComboBoxes bound to a common source, enforcing distinct selections

I'm trying to bind multiple ComboBox's to a common source collection and enforce that once a ComboBox selection is made, that selected item is removed from the other ComboBox's as a possibility. The collection is built dynamically, so I'm doing it i开发者_高级运维n code.

I have tried implementing this in several ways so far, and I just can't seem to come up with something that really works.

I've tried using the default view's Filter predicate, but it only passes the item, and I have no way of knowing which control is doing the filter (and it doesn't even make sense conceptually).

I've tried creating new CollectionView's, but the behavior ends up being different (getting SelectionChange events where I didn't before with the default view).

I've been banging my head against this for hours and it just does not seem to want to work. I would appreciate someone more experienced with WPF helping me out with a working example. I would really like it to not auto-select items from the collection and start blank (otherwise, each ComboBox will have a distinct auto-selection which is far too presumptuous).

I'm really close to just allowing broad selection and validate it later, but this seems like such a simple concept to be having such unbelievable difficulty.

Thanks


Nice question, i thought about it and i would probably approach it with a MultiBinding and a respective ValueConverter, i.e.

<StackPanel>
    <StackPanel.Resources>
        <local:ComboBoxItemsSourceFilter x:Key="ComboBoxItemsSourceFilter"/>
    </StackPanel.Resources>
    <ComboBox Name="cb1">
        <ComboBox.ItemsSource>
            <MultiBinding Converter="{StaticResource ComboBoxItemsSourceFilter}">
                <Binding Path="Emps"/> <!-- Source collection binding -->
                <Binding ElementName="cb2" Path="SelectedItem"/>
                <Binding ElementName="cb3" Path="SelectedItem"/>
            </MultiBinding>
        </ComboBox.ItemsSource>
    </ComboBox>
    <ComboBox Name="cb2">
        <ComboBox.ItemsSource>
            <MultiBinding Converter="{StaticResource ComboBoxItemsSourceFilter}">
                <Binding Path="Emps"/>
                <Binding ElementName="cb1" Path="SelectedItem"/>
                <Binding ElementName="cb3" Path="SelectedItem"/>
            </MultiBinding>
        </ComboBox.ItemsSource>
    </ComboBox>
    <ComboBox Name="cb3">
        <ComboBox.ItemsSource>
            <MultiBinding Converter="{StaticResource ComboBoxItemsSourceFilter}">
                <Binding Path="Emps"/>
                <Binding ElementName="cb1" Path="SelectedItem"/>
                <Binding ElementName="cb2" Path="SelectedItem"/>
            </MultiBinding>
        </ComboBox.ItemsSource>
    </ComboBox>
</StackPanel>
public class ComboBoxItemsSourceFilter : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var collection = new List<object>((object[])values[0]);
        foreach (var item in values.Skip(1))
        {
            if (item != null) collection.Remove(item);
        }
        return collection;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    #endregion
}

Since you do this in code behind adding all those bindings should not be much of a problem, just throw all the comboboxes into a list and you can iterate over them. The converter might need some adjustment since it assumes the input collection (values[0]) can be cast to object[].

This way of doing it sadly causes lots of first-chance-exceptions whose cause i could not determine so far...

A first chance exception of type 'System.Runtime.InteropServices.COMException' occurred in UIAutomationProvider.dll


I'm not exactly sure what I did wrong the first time around, however I did change a few things around and got my original attempt working.

It's possible the problems I was running into were the result of using CollectionView directly, which there is a warning about in the debug output. It states that using CollectionView directly is not fully supported and may have buggy behavior.

I ended up switching to a ListCollectionView. I also created a new List<> containing the contents of my source collection, which allowed me to add a blank object to the list (without changing my original data structure). I simply ignore it on selection change and include it unconditionally in the Filter.

So the steps to making it work:
1) ListCollectionView with source IList
2) Add Filter predicate to the view
3) Create Binding with view as Source
4) combo.SetBinding on ComboBox.ItemsSource
5) On selection changed event, make sure to cast each combo's ItemsSource to an ICollectionView and call Refresh (since it will need to refilter, and property change notifications aren't noticed)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜