为什么我的ListBox会抛出异常?

时间:2009-09-08 20:05:40

标签: c# .net winforms listbox

好的,我能够创建一个简单的Windows窗体项目,它可以重现我发现的一些奇怪的行为。在设计器中,使用ListBox(名为lbx)锚定Top,Left,Right和Bottom以及一个按钮(button1)创建一个表单。现在,Form的代码在这里:

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);
        }
    }
}

请注意以下说明:

运行此选项,单击列表框中的任何项目,然后使用箭头键向下移动足够远以使列表框滚动。 KABOOM。

异常(有时是NullReferenceException,有时是IndexOutOfBoundsException)。有什么想法吗?此外,我认为这些项目是有序的,但它们不是。这只是一个愚蠢的角落案例,Windows Forms无法正确处理,或者我做错了什么?

堆栈追踪:

  

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

     

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

     

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

     

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

     

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

2 个答案:

答案 0 :(得分:1)

我将其复制/粘贴到空表单并获取StackOverflow异常。看着它,通过操作布局事件中的项目,我会说你值得更好。

<击>

我意识到这可能是对其他东西的简化,但是对于你在EDS中可以做的事情只是有限制。

我最好的猜测:ResumeLayout触发递归布局操作。你可以尝试用一个兄弟来阻止它_initFinished,但我建议你在这里重新考虑游览设计。

我复制/粘贴错误,我的错误(使用布局事件)。


第二次尝试:
基于两个while循环,我希望Item字符串按顺序排列,而没有垂直滚动条。很明显,列表框很混乱,显示垂直滚动范围和不按顺序的项目。所以一些'错误'已经存在于Listbox的内部,等待Scroll。我也可以用鼠标重现它。

解决方法:您应该能够使用Resize事件获得所需的效果。

尝试解释:列表框的(非托管部分)被悬浮布局的(多个)Add / RemoveAt操作搞糊涂了。最后的项目绘制在错误的位置,并且列表框无法计算像素到项目。

答案 1 :(得分:0)

你不应该操纵任何GUI元素 构造函数,例如你的例子中有 this.Height + = 100; 。 奇怪的事情可能发生。我被这个咬了 遗留代码中多次。

等到表单加载时间 - 处理base.Load事件并执行 那里的高度操纵。


来自“When does Form.Load event get raised?”:

  问:“......我基本上需要找出答案   两者之间有什么区别   将代码放入Load事件的处理程序中,   而不是把代码放在表格中   之后的构造函数   InitializeComponents()行......“

     

答:“一旦发生了Load事件   控制/形式已经完全   初始化并有一个窗口句柄   创建。因此一旦发生此事件   已经解雇了它是一个完全可用的用户   界面控制。记住这一点   在构造函数里面实际的   控件/窗体的窗口句柄有   尚未创建,你是唯一的   在这里和里面创建C#对象   InitializeComponent调用。“