【问题标题】:Why is my ListBox throwing an exception?为什么我的 ListBox 会抛出异常?
【发布时间】:2009-09-08 20:05:39
【问题描述】:

好的,我能够创建一个简单的 Windows 窗体项目来重现我发现的一些奇怪行为。在设计器中,制作一个带有顶部、左侧、右侧和底部锚定的 ListBox(名为 lbx)和一个按钮 (button1) 的表单。现在,表单的代码在这里:

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

请注意以下说明:

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

异常(有时是 NullReferenceException,有时是 IndexOutOfBoundsException)。任何想法为什么?另外,我认为这些物品会井井有条,但事实并非如此。这只是 Windows 窗体没有正确处理的一个愚蠢的角落案例,还是我做错了什么?

堆栈跟踪:

在 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 索引)

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

【问题讨论】:

  • 请用堆栈信息发布异常。
  • 我运行了代码,但没有收到异常。你得到什么样的异常,它是在哪里抛出的?
  • 毫无例外,我怀疑我们能提供帮助。
  • 由于在布局事件期间修改布局,这听起来像是重入问题。
  • 您使 ListBox 受到它认为无法容忍的不自然行为。结果,它以它知道的唯一方式大声喊叫——除了一个例外。然而,当你把它逼疯的时候,它的叫声是不连贯的。为可怜的列表框哭泣;它没有做任何值得如此残忍的事情。

标签: c# .net winforms listbox


【解决方案1】:

我将它复制/粘贴到一个空表单并得到一个 StackOverflow 异常。看着它,通过对 Layout 事件中的 Items 进行操作,我会说你应该得到更好的结果。

我意识到这可能是对其他事物的简化,但您在 EDS 中可以做的事情是有限的。

我的最佳猜测:ResumeLayout 触发了递归布局操作。您可以尝试使用 _initFinished 的同级来阻止它,但我建议在这里重新考虑游览设计。

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


第二次尝试:
基于两个 while 循环,我希望 Item 字符串是有序的,并且没有垂直滚动条。很明显,列表框很混乱,显示垂直滚动范围并且项目乱序。所以一些“错误”已经出现在列表框的内部,等待滚动。我也可以用鼠标复制它。

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

尝试解释:列表框的(非托管部分)被(多个)Add/RemoveAt 操作与挂起的布局混淆。最后一项绘制在错误的位置,Listbox 无法逐项计算。

【讨论】:

  • 好吧,考虑到正在处理的布局不是列表框,而是表单,我不明白这怎么可能(堆栈溢出)。无论如何,修改 ListBox 的内容不应该影响父窗体的布局。请参阅初始帖子中的 cmets。
  • FMM:修改子表单的布局会导致父表单的布局发生变化。我可以看到堆栈溢出是如何发生的。
  • 允许,但修改列表框的内容不会影响其边界。
  • FMM:没关系。你不能依赖它不告诉它的父级它的布局已经改变 - 这是一个实现细节,即使它的边界没有改变,它也可以这样做。
  • 杰夫:仍然无关紧要 - 我没有遇到堆栈溢出。
【解决方案2】:

您不应在 构造函数,例如this.Height += 100; 在您的示例中。 奇怪的事情可能会发生。我被这个咬过 在遗留代码中多次。

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


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

Q:“……我基本上需要弄清楚 有什么区别 将代码放入 Load 事件的处理程序中, 与将代码放在表单中 之后的构造函数 InitializeComponents() 行..."

A:“Load 事件在 控制/表格已完全 初始化并有一个窗口句柄 创建的。因此一旦这个事件 已解雇它是一个完全可用的用户 界面控制。请记住 在构造函数内部实际 控件/窗体的窗口句柄有 尚未被创造,你只是 在此处和内部创建 C# 对象 InitializeComponent 调用。”

【讨论】:

  • 对不起,不买这个。这正是表单设计器在 InitializeComponent() 中所做的。
  • @FMM 作为一名计算机科学家,您是否购买它是无关紧要的。你试过了吗?结果如何?您能否用结果更新您的问题,以及您可以提供的任何新信息?这将为未来的用户发现更完整的问题和答案。
  • 哇,这是一些严重的死灵帖子 :) 这里有一些已删除的 cmets 不可见,从而掩盖了整个对话。 “您不应该在构造函数中操作任何 GUI 元素”的建议是愚蠢的。 “我不买”可以像“那不可能是正确的”一样容易理解。同样,表单设计器完全按照回答者在InitializeComponent() 中的建议进行操作;因此,答案无效。
猜你喜欢
  • 1970-01-01
  • 2021-04-28
  • 2013-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多