(原创内容,elig首发于博客园,转载请注明出处)
今天在修改一个以前的项目时发现如下问题:
IDE环境 : VS2010
void
frmAdd_Load(
object
sender, EventArgs e)
{
InitializeComboBox();
}
private
void
InitializeComboBox()
{
cboCategory.DropDownStyle
=
ComboBoxStyle.DropDownList;
cboCategory.DataSource
=
mainForm.CategoryList;
cboCategory.DisplayMember
=
“
CategoryName
“
;
cboCategory.ValueMember
=
“
CategoryID
“
;
cboSencondaryCategory.DropDownStyle
=
ComboBoxStyle.DropDownList;
cboSencondaryCategory.DataSource
=
mainForm.SecondaryList;
cboSencondaryCategory.DisplayMember
=
“
SecondaryCategoryName
“
;
cboSencondaryCategory.ValueMember
=
“
SecondaryCategoryID
“
;
//(原创内容,elig首发于博客园,转载请注明出处)
/*
如果没有传进来对应的数据,则按初始值(-1)显示
*/
cboCategory.SelectedIndex
=
1
; //为了方便阅读,这里改为常量显示
cboSencondaryCategory.SelectedIndex
=
1
; //为了方便阅读,这里改为常量显示
}
private
void
cboCategory_SelectedValueChanged(
object
sender, EventArgs e)
{
if
(cboCategory.SelectedIndex
==
–
1
)
{
cboSencondaryCategory.DataSource
=
mainForm.SecondaryList;
cboSencondaryCategory.DisplayMember
=
“
SecondaryCategoryName
“
;
cboSencondaryCategory.ValueMember
=
“
SecondaryCategoryID
“
;
}
else
{
cboSencondaryCategory.DataSource
=
secondaryCategoryBLL.SelectByCategoryID((
int
)cboCategory.SelectedValue);
cboSencondaryCategory.DisplayMember
=
“
SecondaryCategoryName
“
;
cboSencondaryCategory.ValueMember
=
“
SecondaryCategoryID
“
;
}
}
在这种情况下,(int)cboCategory.SelectedValue部分,无论如何得不到正确的结果,一直显示转换出错。照理是不应该有这样的问题的。
经过研究发现,一模一样的代码(cboCategory_SelectedValueChanged()内的内容),在SelectedIndexChanged事件中也一样无法正确获得所需要的结果。
但是,在SelectionChangeCommitted()中则可以正常工作.
(原创内容,elig首发于博客园,转载请注明出处)
于是,我对此做了几个测试.过程如下:
首先,测试几个模块里分别添加如下几行:
id
=
Convert.ToInt32(cboCategory.SelectedValue);
MessageBox.Show(id.ToString());
1.在cboCategory_SelectedIndexChanged() cboCategory_SelectedValueChanged()中添加,编译无法通过,报错如下:
无法将类型为“myProject.Model.Category”的对象强制转换为类型“System.IConvertible”。
2.在普通方法或者load事件里,添加,则可以正常通过。
(原创内容,elig首发于博客园,转载请注明出处)
然后,测试代码改为如下:
=
(Category)(cboCategory.SelectedValue);
if
(id
==
null
)
{
MessageBox.Show(
“
Test
“
);
}
1.在普通方法里调用,第一行可以正确编译通过,id == null 条件成立
2.在load事件,以及SelectionChangeCommitted,SelectedIndexChanged,SelectedValueChanged事件里,都报错如下:
无法将类型为“System.Int32”的对象强制转换为类型“myProject.Model.Category”。
最后,测试如下代码:
String str
=
cboCategory.SelectedValue.ToString();
MessageBox.Show(str);
int
id
=
Convert.ToInt32(str);
MessageBox.Show(id.ToString());
1.load事件 普通方法 以及 SelectionChangeCommitted事件 都可以得到预期结果。
type : System.Int32
2.而SelectionChangeCommitted,SelectedIndexChanged事件里
type : System.Int32
str = myProject.Model.Category
转int后出错
(原创内容,elig首发于博客园,转载请注明出处)
虽然当时没有想明白问题到底出在哪里,但是解决方法就是上面提到的,把需要实现的代码写到SelectionChangeCommitted事件里,就可以正常地得到预期的结果。
项目结束后花了点时间仔细研究了下这个问题,因为同样的代码放在不同的地方却会出现如此丰富多彩的结果,实在让人忍不住。
最后发现,我们如果在SelectedIndexChanged,SelectedValueChanged两者任意一个事件里,把测试代码加到如下if判断里:
if
(cboCategory.SelectedIndex
>=
1
)
{
//
测试代码
}
那么3个事件都能正常编译通过。
注意:问题就出在这个红色的1上,在SelectedIndexChanged,SelectedValueChanged里,只能判断到index >= 1
有人就要问了,comboBox的index不是从0开始的吗?
非常正确!
但是只要把条件改为 >= 0 那么窗体加载时必定报错。
我们来看看这3个事件的区别:
SelectedIndexChanged,SelectedValueChanged是在任何情况下,只要改变了它们监视的值(index或者valueMember)就会触发对应事件
而我们都知道,在控件生成的时候,这2个值不可避免地要发生改变。也就是说,每次改变都会触发这个事件。
而SelectionChangeCommitted事件,官方的翻译解释是:当从下拉列表中选择项而下拉列表关闭时发生。
但是实际是这个翻译是不准确的,因为我装的不是英文的VS环境,所以无从知晓原文如何,但是实际上,该事件个人理解,更准确的翻译是,用户对该控件的选择项作出任何改变时发生。
这个“任何”包括:鼠标点击,获得焦点的情况下方向键上下选择。
(原创内容,elig首发于博客园,转载请注明出处)
在我的问题中,SelectedIndexChanged,SelectedValueChanged无法正确运作,是因为同样的代码在这两个事件中,无法对index = 0的item做处理,或者说SelectedValue的值不明确。从index = 1开始,SelectedValue的(int)转换非常正常。但是正因为这两个事件连系统对comboBox控件作出的改动都会监视,所以不可避免的会在生成第一行的时候即触发事件,导致接触到不正常的index = 0的行。
(原创内容,elig首发于博客园,转载请注明出处)
这个问题应该是一个BUG,如果有朋友知道问题具体出在哪个地方,非常欢迎指出。
关于解决方案:实际上,至少在目前看来,非极端的情况下,都可以用SelectionChangeCommitted事件取代SelectedIndexChanged,SelectedValueChanged。而且如果需要写的代码比较复杂,又没有必要在窗体加载生成comboBox的items集合的时候即触发对应事件,那么没有必要用SelectedIndexChanged,SelectedValueChanged,至少,在加载过程中所触发的事件,属于浪费系统资源的行为。
补充内容:根据@admin的提示,终于把之前的所有问题想通了:
问题如下:其实现在发现,这不是一个BUG。出问题的机制在于:在执行
cboCategory.DataSource = mainForm.CategoryList;
之后,执行下一步之前,因为根据DataSource开始生成comboBox的item生成的时候,就已经触发了SelectedIndexChanged,SelectedValueChanged事件。在这个时候,因为还没有执行到下面的手动指定ValueMember命令。那么,这个时候comboBox的ValueMember则默认为Model.Category类型。
而comboBox有个特点,在生成下拉项之前,它的index是-1,因为尚未有任何项(可以新建一个空白的comboBox然后观察它的SelectedIndex)。在生成之后,先是SelectedIndex会等于0,这也是 我们通常看到的如果在生成之后不指定它的index,则默认是选中第一项的。然后再生成更多的项的时候,被选中的项是不会变的,依然保持第一个。
这就是为什么如果和DisplayMember一起指定了ValueMember的时候,如果if条件里控制了index >= 1的时候才执行相应代码,就不会出错。因为这个时候已经执行完后面的内容了。在
cboCategory.DataSource = mainForm.CategoryList;所产生的动作中,SelectedIndex始终保持着非-1即0的状态。在这个时候始终不会执行SelectedIndexChanged,SelectedValueChanged事件
所以后面的就迎刃而解了
(原创内容,elig首发于博客园,转载请注明出处)
转载于:https://www.cnblogs.com/elig/archive/2011/02/12/1951756.html
今天的文章vba读取第三方软件窗体数据_vba读取第三方软件窗体数据分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/77103.html