• 解决DropDownList常见问题三则


    1,给SelectedValue赋值时,如果Items中没有该项,则报XXX异常;
    2,在绑定时,如果数据源返回null,它将不做任何动作,而我们一般习惯清空;
    3,在绑定到数据源,而数据源参数依赖于别的控件时,会触发两次数据源绑定。

    我的解决方法就是重载DropDownList(比较菜),下面详细说说这三个小问题:

    1,比如某个商品属于某个分类,然后分类被删除了,而商品表中记录的还是原来类别的ID,在绑定DropDownList时,就会报那个常见的异常。这个比较头疼,因为没有太好的办法使用代码控制。我们可以通过重载SelectedValue属性和PerformDataBinding方法来解决:

    代码
            private const String ExceptionString = "(异常)";

            
    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实现(含第三点的实现代码):

    代码
            private Boolean selecting = false;
            
    /// <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,表示顶级地区

    <asp:Parameter DefaultValue="0" Name="parentID" Type="Int32" />

    ;第二个下拉可以使用ControlParameter,依赖于第一个下拉的选择

    <asp:ControlParameter ControlID="DropDownList1" Name="parentID" PropertyName="SelectedValue" Type="Int32" />

    这个时候,如果在FindAllByParentID下断点,会发现第二个下拉触发了两次绑定

    经过一番探索发现:首先是第二个DropDownList的DataBind,触发了ObjectDataSource的Select,而在准备Select的参数的时候,需要调用参数的UpdateValue去取依赖控件的值,正是这个UpdateValue,触发了DataSourceChanged(实际比较复杂,这里为了易懂,从简),然后再次Select……

    看看基类 DataBoundControlPerformSelect方法

    代码
    protected override void 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

    protected override void PerformSelect()
    {
        
    this.OnDataBinding(EventArgs.Empty);
        
    base.RequiresDataBinding = false;
        
    base.MarkAsDataBound();
        
    this.OnDataBound(EventArgs.Empty);
    }

    并且没有调用父类的方法……这也说明了,ListControl之下的几个控件BulletedListCheckBoxListDropDownListListBoxRadioButtonList,全部都存在同样的问题,当然,解决方法也是一样的。

    两年多没写博客了,最近对技术,有点伤感!

  • 相关阅读:
    f(n)=1-1/2+1/3-1/4...+1/n
    练习2-15 求简单交错序列前N项和 (15 分)
    练习2-14 求奇数分之一序列前N项和 (15 分)
    练习2-13 求N分之一序列前N项和 (15 分)
    练习2-12 输出华氏-摄氏温度转换表 (15 分)
    【转载】如何从零开始开发一款嵌入式产品(20年的嵌入式经验分享学习,来自STM32神舟系列开发板设计师的总结
    【转载-Andrew_qian】stm32中断学习
    【转-Andrew_qian】stm32中断嵌套全攻略
    【转】写给自学者的入门指南
    【转】作为一个程序员,数学对你到底有多重要
  • 原文地址:https://www.cnblogs.com/nnhy/p/1727576.html
Copyright © 2020-2023  润新知