好的,我能够创建一个简单的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()
答案 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调用。“