代码改变世界

自己动手做一个支持动态绑定的多选CheckBoxList

2008-04-01 12:53  Loning  阅读(2376)  评论(3编辑  收藏  举报

        有一个项目需要用到checkboxlist的多选,本以为生成几个层然后点点鼠标就搞定的,结果发现麻烦一大堆,因为CheckBoxList不支持多选.
        当我们调用SelectedValue的时候,他默认只返回选中的第一项.然后网上看大多数做法都是在页面内对items遍历然后找被selected的项,但我比较懒,比较喜欢绑定,FormView里面的绑定不用写一堆代码实在是说不过去的.
        于是,对CheckBoxList做个扩展看起来是个不错的方法.
        摆在我面前的有两条路,第一,重新SelectedValue使他支持多个项目,第二,弄一个新的SelectedValues属性.由于有SelectedIndex这种属性,似乎没法让他返回一个数组而不是数,而且我也不想看CheckBoxList都是如何调用这2个属性的,当然还有SelectedItem,所以我选择了后者.
        本着够用就OK的原则,添加了一个属性,SelectedValues,最初的实现方式如下.

public string SelectedValues
        
{
            
get
            
{
                StringBuilder sb 
= new StringBuilder();
                
foreach (ListItem li in this.Items)
                
{
                    
if (li.Selected)
                    
{
                        sb.Append(li.Value);
                        sb.Append(
",");
                    }

                }

                
return sb.ToString();
            }

            
set
            
{
                
string[] values = value.Split(new char[]{','},StringSplitOptions.RemoveEmptyEntries);
                
                
this.ClearSelection();
                
                
foreach (string val in values)
                
{
                    ListItem li 
= this.Items.FindByValue(val);
                    
if (li != null)
                        li.Selected 
= true;
                }

            }

            
        }

然后拖控件,放到FormView里面,弄好DataBinding跟数据源,更新,提交,看看数据库,Roles字段里面出来个"Administrators,"(顺便说一下,这个是用做自定义的一个权限管理的),恩,回去看的时候却发现CheckBoxList还是空的,我晕,Set出问题了.
调试的时候发现value是有的,但是Items.Count==0,突然意识到现在还没有绑定数据....
没办法,看看SelectedValue的实现方法吧..

[Browsable(false), WebCategory("Behavior"), Bindable(true, BindingDirection.TwoWay), DefaultValue(""), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Themeable(false), WebSysDescription("ListControl_SelectedValue")]
public virtual string SelectedValue
{
    
get
    
{
        
int selectedIndex = this.SelectedIndex;
        
if (selectedIndex >= 0)
        
{
            
return this.Items[selectedIndex].Value;
        }

        
return string.Empty;
    }

    
set
    
{
        
if (this.Items.Count != 0)
        
{
            
if ((value == null|| (base.DesignMode && (value.Length == 0)))
            
{
                
this.ClearSelection();
                
return;
            }

            ListItem item 
= this.Items.FindByValue(value);
            
if ((((this.Page != null&& this.Page.IsPostBack) && this._stateLoaded) && (item == null))
            
{
                
throw new ArgumentOutOfRangeException("value", SR.GetString("ListControl_SelectionOutOfRange"new object[] this.ID, "SelectedValue" }));
            }

            
if (item != null)
            
{
                
this.ClearSelection();
                item.Selected 
= true;
            }

        }

        
this.cachedSelectedValue = value;
    }

}

 

cachedSelectedValue,很明显了....他存了一下,肯定DataBound后调用.
于是修改代码,下面贴出完整版:)

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.ComponentModel;
using System.Text;
[assembly: TagPrefix(
"KingCMS.Web.UI""KingCMS")]
namespace KingCMS.Web.UI
{
    [ToolboxData(
"<{0}:LoningCheckBoxList runat=server></{0}:LoningCheckBoxList>")]
    
public class LoningCheckBoxList:CheckBoxList
    
{
        [Category(
"扩展")]
        
private string selectedValues;
        
public string SelectedValues
        
{
            
get
            
{
                StringBuilder sb 
= new StringBuilder();
                
foreach (ListItem li in this.Items)
                
{
                    
if (li.Selected)
                    
{
                        sb.Append(li.Value);
                        sb.Append(
",");
                    }

                }

                
return sb.ToString();
            }

            
set
            
{
                
string[] values = value.Split(new char[]{','},StringSplitOptions.RemoveEmptyEntries);
                selectedValues 
= value;
                
this.ClearSelection();
                
                
foreach (string val in values)
                
{
                    ListItem li 
= this.Items.FindByValue(val);
                    
if (li != null)
                        li.Selected 
= true;
                }

            }

            
        }

        
protected override void OnDataBound(EventArgs e)
        
{
            
base.OnDataBound(e);
            
if (selectedValues != null)
            
{
                
this.ClearSelection();
                
string[] values = selectedValues.Split(new char[] ',' }, StringSplitOptions.RemoveEmptyEntries);
                
foreach (string val in values)
                
{
                    ListItem li 
= this.Items.FindByValue(val);
                    
if (li != null)
                        li.Selected 
= true;
                }

            }

            
        }


    }

}

代码还有很多地方需要改进,比如每次都来个StringBuider,没有缓存等等...不过由于在后台了,所以我认为无所谓的,实现功能好了,如果您有好的改进,拿出来一起分享了:)