我在 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/