Listing shapes in a combobox

Oct 30, 2012 at 10:59 AM

Hi,

I want to list all shapes in a combobox - similar to how Visual Studio lists all controls (above the Property Browser). But the following code doesn't work:

this.comboBox1.DataSource = new List<Shape>();
...
private void display1_ShapesInserted(object sender, DiagramPresenterShapesEventArgs e)
{
    (this.comboBox1.DataSource as List<Shape>).AddRange(e.Shapes.ToList());
}

Debugging shows that after I add one shape to diagram, this.comboBox1.DataSource has Count = 1. However, combobox contains no any items. Why?

Oct 30, 2012 at 5:23 PM
Edited Oct 30, 2012 at 8:48 PM

Guess this problem is related to the nature of a combobox, and "Shape" type is not guilty :) Using generic BindingList helped to solve my problem. Now I have a combobox which has its contents updated when shapes are added to diagram and removed from it. Besides, selecting some shape on the diagram selects the corresponding combobox item, and vice versa. Here is my code, I want to know Your opinion - maybe smth. can be made more effectively:

public partial class Form1 : Form
{
    private class ShapeInfo
    {
        public ShapeInfo(Shape shape)
        {
            this.Shape = shape;
        }

        public Shape Shape { get; set; }

        public override string ToString()
        {
            return this.Shape.GetType().ToString();
        }

        public override bool Equals(object obj)
        {
            ShapeInfo si = obj as ShapeInfo;
            if (si == null)
                return false;
            return this.Shape.Equals(si.Shape);
        }

        public override int GetHashCode()
        {
            return this.Shape.GetHashCode();
        }
    }
    
    private BindingList<ShapeInfo> _shapesBindingList = null;
    ...
    public Form1()
    {
        InitializeComponent();
        ...
        this.comboBox1.SelectedIndexChanged += comboBox1_SelectedIndexChanged;
        _shapesBindingList = new BindingList<ShapeInfo>(new List<ShapeInfo>());
        this.comboBox1.DataSource = _shapesBindingList;
        this.display1.ShapesInserted += display1_ShapesInserted;
        this.display1.ShapesRemoved += display1_ShapesRemoved;
        this.display1.ShapesSelected += display1_ShapesSelected;
        ...
    }
    
    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (this.comboBox1.SelectedItem != null && (this.comboBox1.SelectedItem as ShapeInfo).Shape.Diagram != null)
            this.display1.SelectShape((this.comboBox1.SelectedItem as ShapeInfo).Shape);
    }
    
    private void display1_ShapesSelected(object sender, EventArgs e)
    {
        if (this.display1.SelectedShapes.Count == 1)
        {
            BindingList<ShapeInfo> bList = this.comboBox1.DataSource as BindingList<ShapeInfo>;
            foreach (ShapeInfo si in bList)
            {
                if(si.Shape.Equals(this.display1.SelectedShapes.First()))
                {
                    this.comboBox1.SelectedItem = si;
                    break;
                }
            }
        }
        else
            this.comboBox1.SelectedItem = null;
    }
    
    private void display1_ShapesRemoved(object sender, DiagramPresenterShapesEventArgs e)
    {
        BindingList<ShapeInfo> bList = this.comboBox1.DataSource as BindingList<ShapeInfo>;
        for (int i = bList.Count - 1; i >= 0; i--)
        {
            if (bList[i].Shape.Diagram == null)
            {
                // this shape was deleted from the diagram
                bList.RemoveAt(i);
            }
        }
        /*
         * NOTE: Cannot use this code because e.Shapes is... EMPTY!!!
         *       Is it a bug?! See http://nshape.codeplex.com/discussions/401265
         *       So I had to use a workaround (check Shape.Diagram property).
         *       
        foreach (Shape shape in e.Shapes)
        {
            foreach (ShapeInfo si in bList)
            {
                if (si.Shape.Equals(shape))
                {
                    bList.Remove(si);
                    break;
                }
            }
        }
         */
    }
    
    private void display1_ShapesInserted(object sender, DiagramPresenterShapesEventArgs e)
    {
        foreach (Shape shape in e.Shapes)
        {
            (this.comboBox1.DataSource as BindingList<ShapeInfo>).Add(new ShapeInfo(shape));
        }
    }
}

I had to use BindingList with supplementary type "ShapeInfo" because an attempt to use it with type "Shape" failed: combobox contained only one item: "Collection" :)