【发布时间】:2011-07-11 16:00:10
【问题描述】:
好的,这已经困扰我一段时间了。我想知道其他人如何处理以下情况:
<ComboBox ItemsSource="{Binding MyItems}" SelectedItem="{Binding SelectedItem}"/>
DataContext 对象的代码:
public ObservableCollection<MyItem> MyItems { get; set; }
public MyItem SelectedItem { get; set; }
public void RefreshMyItems()
{
MyItems.Clear();
foreach(var myItem in LoadItems()) MyItems.Add(myItem);
}
public class MyItem
{
public int Id { get; set; }
public override bool Equals(object obj)
{
return this.Id == ((MyItem)obj).Id;
}
}
显然,当调用RefreshMyItems() 方法时,组合框会接收到 Collection Changed 事件,更新其项目并且在刷新的集合中找不到 SelectedItem => 将 SelectedItem 设置为 null。但我需要组合框使用Equals 方法在新集合中选择正确的项目。
换句话说 - ItemsSource 集合仍然包含正确的MyItem,但它是一个new 对象。我希望组合框使用Equals 之类的东西自动选择它(这变得更加困难,因为首先源集合调用Clear() 重置集合并且此时已将SelectedItem 设置为null) .
更新 2 在复制粘贴下面的代码之前,请注意它远非完美!并且注意它默认不绑定两种方式。
更新以防万一有人遇到同样的问题(Pavlo Glazkov 在他的回答中提出的附加属性):
public static class CBSelectedItem
{
public static object GetSelectedItem(DependencyObject obj)
{
return (object)obj.GetValue(SelectedItemProperty);
}
public static void SetSelectedItem(DependencyObject obj, object value)
{
obj.SetValue(SelectedItemProperty, value);
}
// Using a DependencyProperty as the backing store for SelectedIte. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.RegisterAttached("SelectedItem", typeof(object), typeof(CBSelectedItem), new UIPropertyMetadata(null, SelectedItemChanged));
private static List<WeakReference> ComboBoxes = new List<WeakReference>();
private static void SelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ComboBox cb = (ComboBox) d;
// Set the selected item of the ComboBox since the value changed
if (cb.SelectedItem != e.NewValue) cb.SelectedItem = e.NewValue;
// If we already handled this ComboBox - return
if(ComboBoxes.SingleOrDefault(o => o.Target == cb) != null) return;
// Check if the ItemsSource supports notifications
if(cb.ItemsSource is INotifyCollectionChanged)
{
// Add ComboBox to the list of handled combo boxes so we do not handle it again in the future
ComboBoxes.Add(new WeakReference(cb));
// When the ItemsSource collection changes we set the SelectedItem to correct value (using Equals)
((INotifyCollectionChanged) cb.ItemsSource).CollectionChanged +=
delegate(object sender, NotifyCollectionChangedEventArgs e2)
{
var collection = (IEnumerable<object>) sender;
cb.SelectedItem = collection.SingleOrDefault(o => o.Equals(GetSelectedItem(cb)));
};
// If the user has selected some new value in the combo box - update the attached property too
cb.SelectionChanged += delegate(object sender, SelectionChangedEventArgs e3)
{
// We only want to handle cases that actually change the selection
if(e3.AddedItems.Count == 1)
{
SetSelectedItem((DependencyObject)sender, e3.AddedItems[0]);
}
};
}
}
}
【问题讨论】:
-
iv'e 遇到了这个问题并通过以下方式解决了它stackoverflow.com/questions/12337442/…
-
对于那些对这种方法有疑问并且像我一样一开始没有意识到的人:这个解决方案与 nmclean 的答案一起使用可能会更好。
标签: wpf collections combobox selecteditem