silverlight - 绑定(bind)到 ICollectionView 的 ComboBox 显示不正确的 SelectedItem

标签 silverlight mvvm combobox icollectionview

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

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

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

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

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

为了允许这种动态过滤,我有 2 个不同的 ICollectionView在我的 ViewModel 中,每个组合框 ItemsSource势必会。每个ICollectionView有相同的来源ObservableCollection<T>但在过滤器中设置为过滤掉对方的选中项。
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) 已选择 绿色

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

    CB1
  • 蓝色
  • 红色

  • CB2
  • 绿色
  • 红色

  • 如果我在 CB1 中选择 Red,我希望 Red 将从 CB2 中删除,然后 Blue 替换它。这发生正确,但显示的值从绿色变为蓝色。

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

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

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

    有没有人见过这个问题或任何想法我可以解决它?

    最佳答案

    组合框的绑定(bind)至少存在 5 个严重问题。

    在这里,我想你遇到了

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

    这个。

    一旦您更新 itemssource 绑定(bind)将停止工作。

    我使用了那里可用的解决方案之一,这段代码为我解决了这个问题:

    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
        }
    

    它不是我的代码,而是与此错误相关的文章中的一个。

    关于silverlight - 绑定(bind)到 ICollectionView 的 ComboBox 显示不正确的 SelectedItem,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7976062/

    相关文章:

    .net - 在运行时检查.NET堆

    wpf - 具有直接ViewModel切换的WPF/MVVM导航

    c# - 在 WPF C# 中填充 ComboBox 项

    WPF如何更新ViewModel中绑定(bind)到ReadOnly属性的 View

    c# - 我的 Window c# MVVM 的重启按钮

    winapi - 什么是组合框消息 359 0x167?

    c# - 如何更新由另一个组合框触发的组合框中的值?

    c# - 尝试删除独立存储中的目录时出现异常

    c# - 在 C# 中为 Silverlight 的 WriteableBitmap 将 Int 转换为 Color

    Silverlight 数据网格图像