1

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

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

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

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

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

为了允许这种动态过滤,我ICollectionView的 ViewModel 中有 2 个不同的 ',每个组合框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替换它。这发生正确,但显示的值从Green变为Blue

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

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

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

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

4

1 回答 1

0

组合框的绑定至少存在 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
    }

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

于 2011-11-03T12:07:52.173 回答