【问题标题】:Filtered Combobox ItemsSource binding issue过滤的组合框 ItemsSource 绑定问题
【发布时间】:2014-09-15 16:37:23
【问题描述】:

我想要做什么:
我有 2 个组合框,一个“常规”组合框和一个可过滤组合框。在可过滤组合框ItemsSource 上绑定到第一个组合框SelectedItem 的属性。
下面是一些 XAML 来演示这种关系(我删除了一些属性):

<ComboBox Name="cbx_poche" ItemsSource="{Binding DataContext.ListePoches, ElementName=Main}" SelectedItem="{Binding PocheCible}" />
<controls:FilteredComboBox ItemsSource="{Binding SelectedItem.SupportsEligibles, ElementName=cbx_poche}" SelectedItem="{Binding Support}" />

FilteredComboBox 是来自ComboBox 的派生类,灵感来自这些文章:Building a Filtered ComboBox for WPF / WPF auto-filtering combo

用户可以在组合框中输入内容,它会过滤列表以显示匹配的项目。不需要组合框的默认行为(它会自动完成用户键入的内容),这就是派生它的原因。

上面的那些组合框位于ItemsControl 元素中,因为我需要为特定集合中的每个项目设置一行。组合框的SelectedItem 属性绑定到此集合中的项目。

结果:

问题:
它工作得很好......只要你不在第一个组合框中选择相同的项目(如上面的例子:如果我输入一些与上面的组合不匹配的文本,它将被重置)。 一旦几个 FilteredComboBox 链接到第一个组合框中的同一项目(因此绑定到 SelectedItem.SupportsEligibles),在 FilteredComboBox 中键入文本会过滤两个列表。

我知道它为什么会这样,但我不知道如何解决它。所以我尝试了两件事:

代码 1(当前代码): 问题是代码使用列表上的默认视图,因此绑定到此列表的所有控件都将应用相同的过滤器:

protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
    if (newValue != null)
    {
        if (ItemsSourceView != null)
            ItemsSourceView.Filter -= this.FilterPredicate;

        ItemsSourceView = CollectionViewSource.GetDefaultView(newValue);
        ItemsSourceView.Filter += this.FilterPredicate;
    }

    base.OnItemsSourceChanged(oldValue, newValue);
}

代码 2: 所以我的(天真的)想法是从绑定视图中获取本地视图。我很适合过滤,但会破坏绑定(更改第一个组合中的选定项目不会在第一次通过后更新列表)

protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
    if (newValue != null && newValue != ItemsSourceView)
    {
        if (ItemsSourceView != null)
            ItemsSourceView.Filter -= this.FilterPredicate;

        ItemsCollectionViewSource = new CollectionViewSource { Source = newValue };
        ItemsSourceView = ItemsCollectionViewSource.View;
        ItemsSourceView.Filter += this.FilterPredicate;
        this.ItemsSource = ItemsSourceView; // Breaks the binding !!
    }

    base.OnItemsSourceChanged(oldValue, newValue);
}

我被困在这里了。
我正在寻找一些可以用来通知绑定更改的事件或绑定类,以便更新视图。或者也许无需更改 ItemsSource 即可应用视图

【问题讨论】:

    标签: c# wpf xaml binding


    【解决方案1】:

    我最终使用了一个相当蹩脚的解决方法,所以我仍然对聪明的答案感兴趣。

    对于感兴趣的人:我添加了另一个类似的 ItemsSource2 依赖属性(仍然没有找到一个好名字),我在其上绑定了我的项目列表,而不是原来的 ItemsSource

    当此项目源发生更改时,控件会获取一个新的CollectionView(不是默认值)并将其设置为“标准”ItemsSource
    控件的其他元素保持不变(类似于链接文章中的代码)。

    public static readonly DependencyProperty ItemsSource2Property =
       DependencyProperty.Register(
       "ItemsSource2",
       typeof(IEnumerable),
       typeof(FilteredComboBox),
       new UIPropertyMetadata((IEnumerable)null, new PropertyChangedCallback(OnItemsSource2Changed)));
    
    [Bindable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public IEnumerable ItemsSource2
    {
        get { return (IEnumerable)GetValue(ItemsSource2Property); }
        set
        {
            if (value == null)
            {
                ClearValue(ItemsSource2Property);
            }
            else
            {
                SetValue(ItemsSource2Property, value);
            }
        }
    }
    
    private static void OnItemsSource2Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ic = (FilteredComboBox)d;
        var oldValue = (IEnumerable)e.OldValue;
        var newValue = (IEnumerable)e.NewValue;
    
        if (newValue != null)
        {
            //Prevents the control to select the first item automatically
            ic.IsSynchronizedWithCurrentItem = false;
    
            var viewSource = new CollectionViewSource { Source = newValue };
            ic.ItemsSource = viewSource.View;
        }
        else
        {
            ic.ItemsSource = null;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-11
      • 2013-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多