Declined
Last Updated: 01 Oct 2014 12:17 by ADMIN
ADMIN
George
Created on: 26 Feb 2014 16:04
Category:
Type: Bug Report
1
FIX. RadDropDownList - Binding to a INotifyPropertyChanged objects in a BindingList does not reflect property changes
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);
        }
    }

}
1 comment
ADMIN
Ivan Todorov
Posted on: 18 Jun 2014 11:17
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.