DECLINED: When you are implementing IBindingList in a custom collection, you are responsible for subscribing/unsubscribing to the PropertyChanged event of the items and firing the ListChanged event of the collection. RadDropDownList is not updated only if this implementation is missing.
The solution:
protected override void OnInsertComplete(int index, object value)
{
EditableObject c = (EditableObject)value;
c.Parent = this;
c.PropertyChanged += c_PropertyChanged;
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
}
protected override void OnRemoveComplete(int index, object value)
{
EditableObject c = (EditableObject)value;
c.Parent = this;
c.PropertyChanged -= c_PropertyChanged;
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
}
void c_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, this.List.IndexOf(sender)));
}
To reproduce:
Use the following class:
public class NotifyObject : INotifyPropertyChanged
{
private string prop;
public string Prop
{
get { return this.prop; }
set
{
this.prop = value;
this.OnPropertyChanged("Prop");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
Create a BindingList and set a RadDropDownList's data source
private BindingList<NotifyObject> list;
list = new BindingList<NotifyObject>();
for (int i = 0; i < 5; i++)
{
list.Add(new NotifyObject { Prop = i.ToString() });
}
this.DropDownList.ValueMember = this.DropDownList.DisplayMember = "Prop";
this.DropDownList.DataSource = list;
On a button click change on of the items property:
void Button_Click(object sender, EventArgs e)
{
list[0].Prop = "A";
}
You will see that the changes will not take effect.
Workaround:
Use the following custom RadDropDownList:
public class MyDDList : RadDropDownList
{
protected override RadDropDownListElement CreateDropDownListElement()
{
return new MyDDListElement();
}
}
public class MyDDListElement : RadDropDownListElement
{
protected override void WireEvents()
{
base.WireEvents();
this.ListElement.DataLayer.DataView.CollectionChanged += DataView_CollectionChanged;
}
protected override void UnwireEvents()
{
base.UnwireEvents();
this.ListElement.DataLayer.DataView.CollectionChanged -= DataView_CollectionChanged;
}
void DataView_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.ItemChanged && e.ResetReason == CollectionResetReason.Refresh)
{
this.ListElement.GetType().GetMethod("HandleItemsReset", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(this.ListElement, new object[] { e });
}
}
protected override Type ThemeEffectiveType
{
get
{
return typeof(RadDropDownListElement);
}
}
}