多个ComboBox绑定到公共源,强制执行不同的选择

时间:2011-04-20 22:27:14

标签: c# wpf data-binding combobox filter

我正在尝试将多个ComboBox绑定到一个公共源集合,并强制执行一次ComboBox选择后,所选项目将从其他ComboBox中删除。该集合是动态构建的,所以我在代码中进行。

到目前为止,我已尝试以多种方式实现这一点,而我似乎无法想出一些真正有效的方法。

我尝试过使用默认视图的Filter谓词,但它只传递了该项,我无法知道哪个控件正在进行过滤(并且它在概念上甚至没有意义)。

我尝试过创建新的CollectionView,但行为最终会有所不同(使用默认视图获取之前没有的SelectionChange事件。)

我几个小时以来一直在抨击我,但似乎并不想工作。我很感激有经验的WPF帮助我找到一个有效的例子。我真的希望它不会从集合中自动选择项目并开始空白(否则,每个ComboBox都会有一个独特的自动选择,这太过于冒昧了。)

我真的很接近允许广泛选择并在以后验证它,但这似乎是一个如此简单的概念,难以承受如此难以置信的困难。

由于

2 个答案:

答案 0 :(得分:3)

很好的问题,我考虑过它,我可能会使用MultiBinding和相应的ValueConverter接近它,即

<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
}

由于你在代码中执行此操作后面添加所有这些绑定应该不是一个大问题,只需将所有组合框放入一个列表中,你就可以迭代它们。转换器可能需要进行一些调整,因为它假设输入集合(values[0])可以转换为object[]

这种做法令人遗憾地导致许多第一次机会异常,其原因我到目前为止无法确定......

  

UIAutomationProvider.dll中出现'System.Runtime.InteropServices.COMException'类型的第一次机会异常

答案 1 :(得分:1)

我不确定第一次我做错了什么,但是我确实改变了一些事情并且让我原来的尝试工作。

我遇到的问题可能是直接使用CollectionView的结果,在调试输出中有一个警告。它声明直接使用CollectionView并不完全支持,并且可能有错误的行为。

我最终切换到ListCollectionView。我还创建了一个新的List&lt;&gt;包含我的源集合的内容,这允许我将空白对象添加到列表中(不更改我的原始数据结构)。我只是在选择更改时忽略它并将其无条件地包含在Filter中。

使其成功的步骤:
1)带有源IList的ListCollectionView 2)将过滤谓词添加到视图中 3)创建绑定视图作为源
4)ComboBox.ItemsSource上的combo.SetBinding
5)在选择更改事件时,确保将每个组合的ItemsSource转换为ICollectionView并调用Refresh(因为它需要重新过滤,并且不会注意到属性更改通知)