解決DropDownList常見問題三則
1,給SelectedValue賦值時,如果Items中沒有該項(xiàng),則報XXX異常;
2,在綁定時,如果數(shù)據(jù)源返回null,它將不做任何動作,而我們一般習(xí)慣清空;
3,在綁定到數(shù)據(jù)源,而數(shù)據(jù)源參數(shù)依賴于別的控件時,會觸發(fā)兩次數(shù)據(jù)源綁定。
我的解決方法就是重載DropDownList(比較菜),下面詳細(xì)說說這三個小問題:
1,比如某個商品屬于某個分類,然后分類被刪除了,而商品表中記錄的還是原來類別的ID,在綁定DropDownList時,就會報那個常見的異常。這個比較頭疼,因?yàn)闆]有太好的辦法使用代碼控制。我們可以通過重載SelectedValue屬性和PerformDataBinding方法來解決:
代碼
private String cachedSelectedValue;
/// <summary>
/// 已重載。加上未添加到列表的項(xiàng)。
/// </summary>
public override string SelectedValue
{
get
{
return base.SelectedValue;
}
set
{
if (Items.FindByValue(value) == null)
{
// 列表項(xiàng)中并沒有該選項(xiàng),自動加入,并打上異常標(biāo)識
Items.Add(new ListItem(value + ExceptionString, value));
cachedSelectedValue = value;
}
base.SelectedValue = value;
}
}
/// <summary>
/// 綁定數(shù)據(jù)
/// </summary>
/// <param name="dataSource"></param>
protected override void PerformDataBinding(IEnumerable dataSource)
{
base.PerformDataBinding(dataSource);
if (cachedSelectedValue != null)
{
ClearSelection();
// 重新設(shè)置選中項(xiàng)
ListItem item = Items.FindByValue(cachedSelectedValue);
if (item == null)
{
item = new ListItem(cachedSelectedValue + ExceptionString, cachedSelectedValue);
Items.Add(item);
}
item.Selected = true;
}
}
2,在省市兩級下拉聯(lián)動的時候,如果第一級選擇直轄市,沒有下一級城市,第二個下拉就應(yīng)該顯示沒有子城市或者就顯示直轄市,或者干脆清空。而默認(rèn)情況下,DropDownList是不做任何事情的。這個可以重載PerformSelect實(shí)現(xiàn)(含第三點(diǎn)的實(shí)現(xiàn)代碼):
代碼
/// <summary>
/// 已重載。避免綁定時重入該方法
/// </summary>
protected override void PerformSelect()
{
if (selecting) return;
selecting = true;
if (!this.AppendDataBoundItems)
{
// DropDownList在綁定時,如果數(shù)據(jù)源返回null,它將不做任何動作,而我們一般習(xí)慣清空
this.Items.Clear();
}
base.PerformSelect();
selecting = false;
}
3, 仍然是省市兩級下拉聯(lián)動的例子,這兩個DropDownList分別綁定兩個ObjectDataSource,對應(yīng)實(shí)體類的Area.FindAllByParentID(Int32 parentID)。第一個下來可以設(shè)定參數(shù)為固定值0,表示頂級地區(qū)
;第二個下拉可以使用ControlParameter,依賴于第一個下拉的選擇
這個時候,如果在FindAllByParentID下斷點(diǎn),會發(fā)現(xiàn)第二個下拉觸發(fā)了兩次綁定
經(jīng)過一番探索發(fā)現(xiàn):首先是第二個DropDownList的DataBind,觸發(fā)了ObjectDataSource的Select,而在準(zhǔn)備Select的參數(shù)的時候,需要調(diào)用參數(shù)的UpdateValue去取依賴控件的值,正是這個UpdateValue,觸發(fā)了DataSourceChanged(實(shí)際比較復(fù)雜,這里為了易懂,從簡),然后再次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字段就是專門解決這個問題的。也就是說,控件團(tuán)隊已經(jīng)意識到會存在這種問題,所以在這里留了一手。但是為什么這一手沒有生效呢?
我們來看看DropDownList的父類 ListControl,杯具,它重載了PerformSelect:
{
this.OnDataBinding(EventArgs.Empty);
base.RequiresDataBinding = false;
base.MarkAsDataBound();
this.OnDataBound(EventArgs.Empty);
}
并且沒有調(diào)用父類的方法……這也說明了,ListControl之下的幾個控件BulletedList、CheckBoxList、 DropDownList、ListBox、RadioButtonList,全部都存在同樣的問題,當(dāng)然,解決方法也是一樣的。
兩年多沒寫博客了,最近對技術(shù),有點(diǎn)傷感!


浙公網(wǎng)安備 33010602011771號