【问题标题】:ComboBox bound to ICollectionView is displaying incorrect SelectedItem绑定到 ICollectionView 的 ComboBox 显示不正确的 SelectedItem
【发布时间】:2011-11-02 05:11:18
【问题描述】:

我遇到了 Silverlight 4.0 中的一对组合框的问题。

目的是让两个不同的组合框从同一个列表中读取,但如果其中一个选择的任何项目不会显示在另一个中(因为基础属性不允许相同)。

例如(这只是示例代码,但同样代表了它的工作原理)

<ComboBox ItemsSource="{Binding BackgroundColors}"
          SelectedItem="{Binding SelectedBackgroundColor, Mode=TwoWay}" />

<ComboBox ItemsSource="{Binding ForegroundColors}"
          SelectedItem="{Binding SelectedForegroundColor, Mode=TwoWay}" />

为了允许这种动态过滤,我的 ViewModel 中有 2 个不同的 ICollectionView,每个组合框 ItemsSource 都绑定到这些 ICollectionView。每个ICollectionView 都有一个相同的ObservableCollection&lt;T&gt; 的来源,但在过滤器中设置为过滤掉对方的选中项。

private ObservableCollection<Color> _masterColorList;         
public ICollectionView BackgroundColors { get; }
public ICollectionView ForegroundColors { get; }

当在 UI 中更改 SelectedItem 时,ViewModel 属性会更新,作为其中的一部分,相反的 ICollectionView 会通过 .Refresh() 刷新。

例如。

public Color SelectedForegroundColor
{
    get { return _selectedForegroundColor; }
    set
    {
        if (_selectedForegroundColor == value)
            return;

        _selectedForegroundColor = value;

        BackgroundColors.Refresh();

        RaisePropertyChanged(() => SelectedForegroundColor);
    }
}

这允许过滤器重新运行并更改可供选择的内容。

这很好用,但是有一个问题:

假设我们的主列表中有 3 种颜色:

  • 蓝色
  • 绿色
  • 红色

已选择组合框 1 (CB1) 蓝色 组合框 2 (CB2) 已选择 Green

因此组合框有这些列表(粗体被选中)

CB1

  • 蓝色
  • 红色

CB2

  • 绿色
  • 红色

如果我随后在 CB1 中选择 Red,我希望 Red 将从 CB2 中删除,并用 Blue 替换它。这发生正确,但显示的值从 Green 变为 Blue

基础绑定值没有改变,并且 ICollectionView.CurrentItem 是正确的,但显示显然显示了错误的值。

我认为正在发生的事情是,因为 Green 在列表中较早,所以它与所显示的内容混淆了。如果您对 ICollectionView 进行排序,也会发生这种情况。

我已尝试为更改的组合框和选定项重新引发属性更改事件通知,但这似乎不起作用。

以前有没有人见过这个问题,或者有什么想法可以解决它?

【问题讨论】:

    标签: silverlight mvvm combobox icollectionview


    【解决方案1】:

    至少有 5 个与组合框绑定有关的严重问题。

    这里我想你遇到了

    http://connect.microsoft.com/VisualStudio/feedback/details/523394/silverlight-forum-combobox-selecteditem-binding

    这个。

    一旦你更新 itemssource 绑定就会停止工作。

    我使用了其中一种可用的解决方案,这段代码为我解决了这个问题:

    public class ComboBoxEx : ComboBox
        {
            #region Fields
    
            private bool _suppressSelectionChangedUpdatesRebind = false;
    
            #endregion
    
            #region Properties
    
            public static readonly DependencyProperty SelectedValueProperProperty =
                DependencyProperty.Register(
                    "SelectedValueProper",
                    typeof(object),
                    typeof(ComboBoxEx),
                    new PropertyMetadata((o, dp) => {
                                              var comboBoxEx = o as ComboBoxEx;
                                              if (comboBoxEx == null)
                                                  return;
    
                                              comboBoxEx.SetSelectedValueSuppressingChangeEventProcessing(dp.NewValue);
                                          }));
    
            [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
            public object SelectedValueProper
            {
                get { return GetValue(SelectedValueProperProperty); }
                set { SetValue(SelectedValueProperProperty, value); }
            }
    
            #endregion
    
            #region Constructor and Overrides
    
            public ComboBoxEx()
            {
                SelectionChanged += ComboBoxEx_SelectionChanged;
            }
    
            /// <summary>
            /// Updates the current selected item when the <see cref="P:System.Windows.Controls.ItemsControl.Items"/> collection has changed.
            /// </summary>
            /// <param name="e">Contains data about changes in the items collection.</param>
            protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                // Must re-apply value here because the combobox has a bug that 
                // despite the fact that the binding still exists, it doesn't 
                // re-evaluate and subsequently drops the binding on the change event
                SetSelectedValueSuppressingChangeEventProcessing(SelectedValueProper);
            }
    
            #endregion
    
            #region Events
    
            private void ComboBoxEx_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                // Avoid recursive stack overflow
                if (_suppressSelectionChangedUpdatesRebind)
                    return;
    
                if (e.AddedItems != null && e.AddedItems.Count > 0) {
                    //SelectedValueProper = GetMemberValue( e.AddedItems[0] );
                    SelectedValueProper = SelectedValue; // This is faster than GetMemberValue
                }
                // Do not apply the value if no items are selected (ie. the else)
                // because that just passes on the null-value bug from the combobox
            }
    
            #endregion
    
            #region Helpers
    
            /// <summary>
            /// Gets the member value based on the Selected Value Path
            /// </summary>
            /// <param name="item">The item.</param>
            /// <returns></returns>
            private object GetMemberValue(object item)
            {
                return item.GetType().GetProperty(SelectedValuePath).GetValue(item, null);
            }
    
            /// <summary>
            /// Sets the selected value suppressing change event processing.
            /// </summary>
            /// <param name="newSelectedValue">The new selected value.</param>
            private void SetSelectedValueSuppressingChangeEventProcessing(object newSelectedValue)
            {
                try {
                    _suppressSelectionChangedUpdatesRebind = true;
                    SelectedValue = newSelectedValue;
                }
                finally {
                    _suppressSelectionChangedUpdatesRebind = false;
                }
            }
    
            #endregion
        }
    

    这不是我的代码,而是来自与此错误相关的文章。

    【讨论】:

    • 不幸的是,这个或该连接站点上的任何其他解决方法似乎都不起作用。我相信 SelectedItem/SelectedValue 绑定仍然有效,但 Combobox 上的视觉显示不正确。
    • 哦。好吧,我可以建议不要绑定到 ICollectionView,而是尝试更简单的方法,例如 IEnumerable(对于初学者),我在这里遇到了 CollectionViewSource 的大错误stackoverflow.com/questions/6305608/… 组合框绑定存在很多问题。我会想到其他可能的原因。
    • 是的,在我们的代码的更新版本中,我们将更改回 ObservableCollection。只是一个超级烦人的错误:/
    • 在 silverlight 中绑定到组合框就像我在编程生涯中遇到的最糟糕的事情。问题太多了。。还没有解决。它也很烦人,因为你完全没想到它会这么麻烦。
    猜你喜欢
    • 2013-09-19
    • 2020-01-24
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 2019-11-10
    • 2023-04-03
    • 1970-01-01
    相关资源
    最近更新 更多