今天偶尔复习下WinForm开发,在用到ComboBox下拉框的时候,想用SelectedIndexChanged事件根据选中内容动态展示不同的数据,需求很简单,但是竟然出错了,后来发现其实就是SelectedIndexChanged事件执行时间问题导致的,那如何解决呢,请看下面的分析。
一、DataBind()方法就是给下拉框绑定的方法(这里为了让下拉框默认不选中,设置了SelectedIndex = -1)这个位置就是出问题的地方
//数据绑定
private void DataBind()
{
//角色权限设置绑定下拉列表
this.cboRoleList.DataSource = null;
this.cboRoleList.DataSource = objAdminRole;
this.cboRoleList.DisplayMember = "RoleName";
this.cboRoleList.ValueMember = "RoleId";
//去掉下拉列表的默认值
this.cboRoleList.SelectedIndex = -1;
}
二、这里触发了 SelectedIndexChanged事件,实现根据选中内容不同实现不同的切换(方法内部实现的啥可以不用关心)
//下拉列表改变时触发的事件
private void cboRoleList_SelectedIndexChanged(object sender, EventArgs e)
{
this.tvRightList.Nodes.Clear();
List<FirstMenu> GetAllFirstMenuRoleId = objRightManager.GetAllFirstMenu(((AdminRole)(this.cboRoleList.SelectedItem)).RoleId);
for (int i = 0; i < GetAllFirstMenuRoleId.Count; i++)
{
TreeNode objNode = new TreeNode()
{
Name = GetAllFirstMenuRoleId[i].FirstMenuId.ToString(),
Text=GetAllFirstMenuRoleId[i].DisplayName
};
List<SecondMenu> GetAllSecondMenuRoleId = objRightManager.GetAllSecondMenu(GetAllFirstMenuRoleId[i].FirstMenuId, ((AdminRole)(this.cboRoleList.SelectedItem)).RoleId);
for (int j = 0; j < GetAllSecondMenuRoleId.Count; j++)
{
objNode.Nodes.Add(new TreeNode() {
Name= GetAllSecondMenuRoleId[j].SecondMenuId.ToString(),
Text=GetAllSecondMenuRoleId[j].DisplayName,
ForeColor=Color.Blue
});
List<RightList> GetAllRightListRoleId = objRightManager.GetAllRightList(GetAllSecondMenuRoleId[j].SecondMenuId, ((AdminRole)(this.cboRoleList.SelectedItem)).RoleId);
for (int k = 0; k < GetAllRightListRoleId.Count; k++)
{
objNode.Nodes[j].Nodes.Add(new TreeNode() {
Name=GetAllRightListRoleId[k].RightId.ToString(),
Text=GetAllRightListRoleId[k].RightName,
ForeColor=Color.Red,
Tag=GetAllRightListRoleId[k].RightCode
});
}
}
this.tvRightList.Nodes.Add(objNode);
}
//将整个节点展开
this.tvRightList.ExpandAll();
}
三、在这里定义了GetAllRoleRight()方法,这个方法本身在窗体初始化之后立即调用,方法内部是调用了上面的DataBind()方法。这时候就会出错,报的错误就是最常见的"未将对象引用到对象实例",
//绑定当前系统全部角色
public void GetAllRoleRight()
{
//为角色集合添加数据库全部角色
objAdminRole =objRightManager.GetAllRole();
//数据绑定
DataBind();
}
错误原因:
SelectedIndexChanged事件是在绑定的时候就会触发,意思就是在设置SelectedIndex = -1的时候事件就已经被触发了,并立即调用步骤二中的事件响应方法cboRoleList_SelectedIndexChanged,而这时候,该方法第二行:List<FirstMenu> GetAllFirstMenuRoleId = objRightManager.GetAllFirstMenu(((AdminRole)(this.cboRoleList.SelectedItem)).RoleId);还没有来得及获得任何数据,故此时,程序会立即报错:未将对象引用到对象的实例。好了原因分析清楚了,那就说一下解决办法。
解决办法:手动断开/连接事件响应方法
在调用 DataBind()方法(设置SelectedIndex = -1)之前,即调用cboRoleList_SelectedIndexChanged()事件响应方法之前,断开事件与事件响应方法的关联,之后在调用后,再将事件与事件响应方法进行关联就好了。将方法三代码加两句(如下)
//绑定当前系统全部角色
public void GetAllRoleRight()
{
//先将(下拉列表改变时触发的事件)事件解绑
this.cboRoleList.SelectedIndexChanged -= new System.EventHandler(this.cboRoleList_SelectedIndexChanged);
//为角色集合添加数据库全部角色
objAdminRole =objRightManager.GetAllRole();
//数据绑定
DataBind();
//再将(下拉列表改变时触发的事件)事件添加绑定
this.cboRoleList.SelectedIndexChanged += new System.EventHandler(this.cboRoleList_SelectedIndexChanged);
}
这样在调用 DataBind()方法(设置SelectedIndex = -1)(即调用cboRoleList_SelectedIndexChanged()事件响应方法)时候就不会触发SelectedIndexChanged事件。就不会报错了。