1

Silverlight 4.0 のコンボ ボックスのペアに問題があります。

意図は、同じリストから読み取る 2 つの異なるコンボボックスを持つことですが、一方で選択されたアイテムが他方に表示されない場合 (基本的なプロパティが同じであることは許可されていないため)。

例 (これは単なるサンプル コードですが、同じように動作することを表しています)

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

SelectedItem が UI で変更されると、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 で赤を選択すると、が CB2 から削除され、がそれを置き換えると予想されます。これは正しく行われますが、表示される値がGreenからBlueに変わります。

基になるバインドされた値は変更されず、ICollectionView.CurrentItem は正しいですが、ディスプレイには明らかに間違った値が表示されています。

私が考えているのは、緑がリストの前にあるため、表示されているものと混同されているということです. ICollectionView を並べ替えている場合にも発生します。

変更中のコンボボックスと選択したアイテムのプロパティ変更イベント通知を再発生させようとしましたが、うまくいかないようです。

誰かがこの問題を以前に見たことがありますか、またはそれを修正する方法はありますか?

4

1 に答える 1

0

コンボボックスのバインドには少なくとも 5 つの深刻な問題があります。

ここで私はあなたが遭遇したと思います

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

これです。

アイテムを更新すると、ソースバインディングが機能しなくなります。

そこで利用可能なソリューションの1つを使用しました。このコードはこの問題を解決しました:

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 に答える