解决DropDownList常见问题三则
1,给SelectedValue赋值时,如果Items中没有该项,则报XXX异常;
2,在绑定时,如果数据源返回null,它将不做任何动作,而我们一般习惯清空;
3,在绑定到数据源,而数据源参数依赖于别的控件时,会触发两次数据源绑定。
我的解决方法就是重载DropDownList(比较菜),下面详细说说这三个小问题:
1,比如某个商品属于某个分类,然后分类被删除了,而商品表中记录的还是原来类别的ID,在绑定DropDownList时,就会报那个常见的异常。这个比较头疼,因为没有太好的办法使用代码控制。我们可以通过重载SelectedValue属性和PerformDataBinding方法来解决:

private String cachedSelectedValue;
/// <summary>
/// 已重载。加上未添加到列表的项。
/// </summary>
public override string SelectedValue
{
get
{
return base.SelectedValue;
}
set
{
if (Items.FindByValue(value) == null)
{
// 列表项中并没有该选项,自动加入,并打上异常标识
Items.Add(new ListItem(value + ExceptionString, value));
cachedSelectedValue = value;
}
base.SelectedValue = value;
}
}
/// <summary>
/// 绑定数据
/// </summary>
/// <param name="dataSource"></param>
protected override void PerformDataBinding(IEnumerable dataSource)
{
base.PerformDataBinding(dataSource);
if (cachedSelectedValue != null)
{
ClearSelection();
// 重新设置选中项
ListItem item = Items.FindByValue(cachedSelectedValue);
if (item == null)
{
item = new ListItem(cachedSelectedValue + ExceptionString, cachedSelectedValue);
Items.Add(item);
}
item.Selected = true;
}
}
2,在省市两级下拉联动的时候,如果第一级选择直辖市,没有下一级城市,第二个下拉就应该显示没有子城市或者就显示直辖市,或者干脆清空。而默认情况下,DropDownList是不做任何事情的。这个可以重载PerformSelect实现(含第三点的实现代码):

/// <summary>
/// 已重载。避免绑定时重入该方法
/// </summary>
protected override void PerformSelect()
{
if (selecting) return;
selecting = true;
if (!this.AppendDataBoundItems)
{
// DropDownList在绑定时,如果数据源返回null,它将不做任何动作,而我们一般习惯清空
this.Items.Clear();
}
base.PerformSelect();
selecting = false;
}
3, 仍然是省市两级下拉联动的例子,这两个DropDownList分别绑定两个ObjectDataSource,对应实体类的Area.FindAllByParentID(Int32 parentID)。第一个下来可以设定参数为固定值0,表示顶级地区
;第二个下拉可以使用ControlParameter,依赖于第一个下拉的选择
这个时候,如果在FindAllByParentID下断点,会发现第二个下拉触发了两次绑定
经过一番探索发现:首先是第二个DropDownList的DataBind,触发了ObjectDataSource的Select,而在准备Select的参数的时候,需要调用参数的UpdateValue去取依赖控件的值,正是这个UpdateValue,触发了DataSourceChanged(实际比较复杂,这里为了易懂,从简),然后再次Select……
看看基类 DataBoundControl的PerformSelect方法

{
if (this.DataSourceID.Length == 0)
{
this.OnDataBinding(EventArgs.Empty);
}
DataSourceView data = this.GetData();
this._arguments = this.CreateDataSourceSelectArguments();
this._ignoreDataSourceViewChanged = true;
base.RequiresDataBinding = false;
this.MarkAsDataBound();
data.Select(this._arguments, new DataSourceViewSelectCallback(this.OnDataSourceViewSelectCallback));
}
很明显,_ignoreDataSourceViewChanged字段就是专门解决这个问题的。也就是说,控件团队已经意识到会存在这种问题,所以在这里留了一手。但是为什么这一手没有生效呢?
我们来看看DropDownList的父类 ListControl,杯具,它重载了PerformSelect:
{
this.OnDataBinding(EventArgs.Empty);
base.RequiresDataBinding = false;
base.MarkAsDataBound();
this.OnDataBound(EventArgs.Empty);
}
并且没有调用父类的方法……这也说明了,ListControl之下的几个控件BulletedList、CheckBoxList、 DropDownList、ListBox、RadioButtonList,全部都存在同样的问题,当然,解决方法也是一样的。
两年多没写博客了,最近对技术,有点伤感!
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2007-05-04 在递归函数中因不正确使用公共变量而形成死循环