views:

135

answers:

1

Hi All,

I am facing this problem with default CollectionEditor.

When I add items to the collection editor, I display the items as a rectangle on the user control. But when I delete the items that were present already the preview does not gets updated untill i click on OK or Add button.

I have provided the code for the same below.

Steps to produce:

  1. Add a control to from.
  2. Edit the Collection property of the control by opening CollectionEditor and adding (say 3. items. (U see the items getting added to the control). The preview gets updated nicely.
  3. Now click on OK button.
  4. Re-open the CollectionEditor and try deleting the existing item. I would expect the items being deleted in the preview. But the deleted items remains on the control till I click on 'Add' button or 'OK' button. :(

Is this is a bug in the CollectionEditor class?

Source Code:

TestCollectionClass.cs

using System; using System.Collections; using System.ComponentModel; using System.Drawing.Design; using System.Globalization; using System.Security.Permissions; using System.Windows.Forms; using System.Drawing;

namespace TestCollectionEditor { using T = TestComponent;

[
    Editor("", typeof(UITypeEditor)),
    ListBindable(false)
]
public class TestCollectionClass : IList, ICollection, IEnumerable
{
    private IList _list;
    private Size _renderFrame;

    public delegate void CollectionChangeEventHandler(object sender, EventArgs e);
    public event CollectionChangeEventHandler _onCollectionChanged;
    public event CollectionChangeEventHandler CollectionChanged
    {
        add
        {
            lock (this)
            {
                _onCollectionChanged += value;
            }
        }
        remove
        {
            lock (this)
            {
                _onCollectionChanged -= value;
            }
        }
    }

    protected virtual void OnCollectionChanged(EventArgs e)
    {
        if (_onCollectionChanged != null)
        {
            _onCollectionChanged(this, e);
        }
    }

    public TestCollectionClass(Size size)
    {
        _list = new ArrayList();
        _renderFrame = size;
    }

    public TestCollectionClass(T[] item)
        : this(new Size(100, 100))
    {
        AddRange(item);
    }

    public TestCollectionClass(TestCollectionClass item)
        : this(new Size(100, 100))
    {
        AddRange(item);
    }

    public override string ToString()
    {
        return String.Format(CultureInfo.CurrentCulture, "{0}: Count={1}", GetType().Name, Count);
    }

    public T this[int index]
    {
        get { return (T)_list[index]; }
        set
        {
            _list[index] = value;
        }
    }

    object IList.this[int index]
    {
        get { return this[index]; }
        set
        {
            T item = value as T;
            if (item == null)
                throw GetInvalidTypeException(value);

            this[index] = item;
        }
    }

    public int Add(T item)
    {
        if (item == null)
        {
            throw new ArgumentNullException("item");
        }

        int i = _list.Add(item);
        OnCollectionChanged(new EventArgs());
        return i;
    }

    int IList.Add(object item)
    {
        T value = item as T;
        if (value == null)
            throw GetInvalidTypeException(item);

        return Add(value);
    }

    public void AddRange(T[] item)
    {
        if (item == null)
            throw new ArgumentNullException("item");

        foreach (T current in item)
            Add(current);
    }

    public void AddRange(TestCollectionClass item)
    {
        if (item == null)
            throw new ArgumentNullException("item");

        foreach (T current in item)
            Add(current);
    }

    public void Clear()
    {
        _list.Clear();
        OnCollectionChanged(new EventArgs());
    }

    public int Count
    {
        get { return _list.Count; }
    }

    public bool Contains(T item)
    {
        if (item == null)
        {
            return false;
        }

        return _list.Contains(item);
    }

    bool IList.Contains(object item)
    {
        T value = item as T;
        if (value == null)
            throw GetInvalidTypeException(item);

        return Contains(value);
    }

    public void CopyTo(T[] array, int index)
    {
        ICollection collection = this as ICollection;
        collection.CopyTo(array, index);
    }

    void ICollection.CopyTo(System.Array array, int index)
    {
        if (array == null)
        {
            throw new ArgumentNullException("array");
        }

        _list.CopyTo(array, index);
    }

    public int IndexOf(T item)
    {
        if (item == null)
        {
            return -1;
        }

        return _list.IndexOf(item);
    }

    int IList.IndexOf(object item)
    {
        T value = item as T;
        if (value == null)
            throw GetInvalidTypeException(item);

        return IndexOf(value);
    }

    public void Insert(int index, T item)
    {
        if (item == null)
        {
            throw new ArgumentNullException("item");
        }

        _list.Insert(index, item);
        OnCollectionChanged(new EventArgs());
    }

    void IList.Insert(int index, object item)
    {
        T value = item as T;
        if (value == null)
            throw GetInvalidTypeException(item);

        Insert(index, value);
    }

    bool ICollection.IsSynchronized
    {
        get { return IsSynchronized; }
    }

    protected bool IsSynchronized
    {
        get { return _list.IsSynchronized; }
    }

    bool IList.IsFixedSize
    {
        get { return IsFixedSize; }
    }

    protected bool IsFixedSize
    {
        get { return _list.IsFixedSize; }
    }

    bool IList.IsReadOnly
    {
        get { return IsReadOnly; }
    }

    protected bool IsReadOnly
    {
        get { return _list.IsReadOnly; }
    }

    object ICollection.SyncRoot
    {
        get { return SyncRoot; }
    }

    protected object SyncRoot
    {
        get { return _list.SyncRoot; }
    }

    public IEnumerator GetEnumerator()
    {
        return _list.GetEnumerator();
    }

    public void Remove(T item)
    {
        if (item != null)
        {
            _list.Remove(item);
            OnCollectionChanged(new EventArgs());
        }
    }

    void IList.Remove(object item)
    {
        T value = item as T;
        if (value == null)
            throw GetInvalidTypeException(item);

        Remove(value);
    }

    public void RemoveAt(int index)
    {
        _list.RemoveAt(index);
        OnCollectionChanged(new EventArgs());
    }

    private static Exception GetInvalidTypeException(object obj)
    {
        return new NotSupportedException();
    }
}

}

TestComponent.cs

using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Drawing;

namespace TestCollectionEditor {
public partial class TestComponent : Component { public TestComponent() { InitializeComponent(); _position = new Point(random.Next(), random.Next()); _size = new Size(100, 100); _color = Color.FromArgb(random.Next()%255,random.Next()%255,random.Next()%255); }

    public TestComponent(IContainer container)
    {
        container.Add(this);
        _position = new Point(random.Next(), random.Next());
        _size = new Size(10, 10);

        InitializeComponent();
    }

    private Point _position;
    private Size _size;
    private Color _color;
    private static Random random = new Random();

    public Color Color
    {
        get
        {
            return _color;
        }
    }

    public Point Position
    {
        get
        {
            return _position;
        }
    }

    public Size Size
    {
        get
        {
            return _size;
        }
    }

    public void Draw(Graphics g, Size renderFrame)
    {
        Point newPosition = new Point(Position.X % renderFrame.Width, Position.Y % renderFrame.Height);
        g.FillRectangle(new SolidBrush(Color), new Rectangle(newPosition, Size));
    }

    private void InitializeComponent()
    {
    }
}

}

CollectionEditorTestUserControl.cs

using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms;

namespace TestCollectionEditor { public partial class CollectionEditorTestUserControl : UserControl { public CollectionEditorTestUserControl() { //this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; _collection = new TestCollectionClass(Size); _collection.CollectionChanged += new TestCollectionClass.CollectionChangeEventHandler(OnCollectionChanged); InitializeComponent(); }

    private void OnCollectionChanged(object sender, EventArgs e)
    {
        Invalidate();
    }

    private TestCollectionClass _collection;
    public TestCollectionClass Collection
    {
        get
        {
            return _collection;
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        for (int i = 0; i < _collection.Count; i++ )
        {
            TestComponent c = _collection[i];
            c.Draw(e.Graphics, Size);
        }
    }
}

}

A: 

Might be a bug, especially if Add is dynamic and Delete isn't. The OnCollectionChanged notification is probably just a "add new items" loop, without taking deletes into account. So that is why added items work.

Without looking at the implementation I'd expect that the collection you are editing is a copy of the one in the control. When OK/Add is clicked, then the modified collection is copied back to your property. This is when the deletes take effect.

devstuff