Why is my ListBox throwing an exception?

Ok, I was able to create a simple Windows Forms project that reproduces some strange behavior that I found. In the designer, create a form with ListBox rows (named lbx), top, left, right, and bottom, and a button (button1). Now the form code is here:

using System;
using System.Windows.Forms;

namespace ListBoxKaboom
{
    public partial class Form1 : Form
    {
        private bool _initFinished = false;

        public Form1()
        {
            InitializeComponent();

            this._initFinished = true;

            this.Height += 100;
            this.Height -= 50;
            this.Height += 50;
        }

        private void lbx_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.button1.Enabled = (this.lbx.SelectedItem != null);
        }

        protected override void OnLayout(LayoutEventArgs e)
        {
            if (_initFinished)
            {
                int lines = (this.lbx.Height - 4) / this.lbx.ItemHeight;

                this.SuspendLayout();
                while (lines < this.lbx.Items.Count)
                {
                    this.lbx.Items.RemoveAt(this.lbx.Items.Count - 1);
                }

                while (lines > this.lbx.Items.Count)
                {
                    this.lbx.Items.Add("Item " + (this.lbx.Items.Count + 1).ToString());
                }
                this.ResumeLayout();
            }

            base.OnLayout(e);
        }
    }
}

      

PLEASE REFER TO THE FOLLOWING INSTRUCTIONS:

Run this, click any of the items in the list, and use the arrow keys to move down far enough for the list box to scroll . Kaboom.

Exception (sometimes NullReferenceException and sometimes IndexOutOfBoundsException). Any ideas why? Also, I think the items will be ok, but they are not. Is this just a dumb corner case that wasn't being handled properly by Windows Forms, or am I doing something wrong?

Stack trace:

at System.Windows.Forms.ListBox.NativeUpdateSelection ()

at System.Windows.Forms.ListBox.SelectedObjectCollection.EnsureUpToDate ()

at System.Windows.Forms.ListBox.SelectedObjectCollection.get_InnerArray ()

at System.Windows.Forms.ListBox.SelectedObjectCollection.get_Item (Int32 index)

at System.Windows.Forms.ListBox.get_SelectedItem ()

0


source to share


2 answers


I copy / paste it into a blank form and get a StackOverflow exception. Looking at this, manipulating elements within the layout, I would say that you deserve a little better.

I understand that this might be a simplification of something else, but there are simply limits to what you can do in EDS.

My best guess: ResumeLayout triggers a recursive layout operation. You could try to stop it with a brother at _initFinished, but I would suggest revisiting the tour design here.

I copy / paste wrong, mine is bad (layout event is used).




Second try:
Based on the two while-loops, I would expect the Item lines to be ok and there is no vertical scrollbar. It is clear that the listbox is confusing, shows a vertical scroll range and the items are out of order. So some "bug" is already present in the inner elements of the Listbox waiting for scrolling. I can also play it with the mouse.

Workaround: you can get the desired effect using the Resize event.

Attempt to explain: (unmanaged part) Listbox gets confused with (multiple) Add / RemoveAt operations with suspended layout. The last items are drawn in the wrong place and the Listbox cannot compute pixel-to-item.

+1


source


You shouldn't be manipulating GUI elements in a constructor for example. this.Height + = 100; in your example. Strange things can happen. I've been bitten by this several times in legacy code.

Wait for the form to load - handle the base.Load event and do there manipulation of the height.




From " When does Form.Load event occur? ":

Q: "... I need to know basically what the difference is between putting code in the Load event handler, versus putting code in the form's constructor after the InitializeComponents () line ..."

A: "The load event is triggered after the control / form is fully initialized and has a window handle created. Therefore, as soon as this event is dismissed, it is a fully functional user interface control. Remember that inside the constructor the window handle for the control / form has not been created yet, you only creating C # objects here and inside the InitializeComponent call. "

0


source







All Articles