支持树型的GridView控件

 

支持树型的GridView

实现思路: 继承自Gridview,处理gridview的数据源,使其在帮定时,就已经按照树型菜单顺序排列好,那样只需在帮定处理其图片是javascript脚本就可以了

源代码下载:http://files.cnblogs.com/wschacker/TreeListView.rar

效果图:

代码:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
using System;
    
using System.Data;
    
using System.Collections;
    
using System.Collections.Specialized;
    
using System.Collections.Generic;
    
using System.ComponentModel;
    
using System.Text;
    
using System.Web;
    
using System.IO;
    
using System.Drawing;
    
using System.Drawing.Design;
    
using System.Reflection;
    
using System.Web.UI;
    
using System.Web.UI.WebControls;
    
using System.Web.UI.HtmlControls;
    [ToolboxData(
"<{0}:TreeListView runat=server></{0}:TreeListView>"), DefaultProperty("Text")]
    
public class TreeListView : GridView, IPostBackDataHandler
ExpandedBlockStart.gifContractedBlock.gif    
{
        
public TreeListView()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
base.AllowPaging = false;
            
base.AllowSorting = false;
            
base.AutoGenerateColumns = false;

        }


ContractedSubBlock.gifExpandedSubBlockStart.gif        
Tree的属性设置#region Tree的属性设置
        
private int _nodeColumnIndex;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 显示树型的列 Index
        
/// </summary>

        public int NodeColumnIndex
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return this._nodeColumnIndex; }
            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _nodeColumnIndex 
= value;
            }

        }


        
private string _columnKey;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// Key字段
        
/// </summary>

        public string ColumnKey
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _columnKey; }
            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _columnKey 
= value;
            }

        }


        
private string _parentKey;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 指向父节点的字段
        
/// </summary>

        public string ParentKey
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _parentKey 
= value;
            }

        }


        
private string _sortKey;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 排序字段
        
/// </summary>

        public string SortKey
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set { _sortKey = value; }
        }


        
private object _rootNodeFlag;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 根节点的标记 这里采用 ParentKey为什么字符
        
/// </summary>

        public object RootNodeFlag
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _rootNodeFlag 
= value;
            }

        }


        
private static string _treeImageFolder = "/Images/Tree/";
        
public static string TreeImageFolder
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return _treeImageFolder;
            }

            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _treeImageFolder 
= value;
            }

        }


        
private int _expendDepth = 0;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 展开的深度
        
/// </summary>

        public int ExpendDepth
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return _expendDepth;
            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
set { _expendDepth = value; }
        }

        
#endregion


        
public override object DataSource
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return base.DataSource;
            }

            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                DataTable dtSource 
= new DataTable();
                
if (value is DataSet && ((DataSet)value).Tables.Count > 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    DataSet ds 
= value as DataSet;
                    dtSource 
= OrderData(ds.Tables[0]);
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
throw new Exception("DataSource is not DataSet!");
                }

                
base.DataSource = dtSource;
            }

        }


        DataTable OrderData(DataTable dtSource)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            DataTable dtResult 
= dtSource.Clone();
            dtResult.Columns.Add(
"TreeListView$Row$Depth"typeof(int));
            dtResult.Columns.Add(
"TreeListView$Row$IsLeaf"typeof(bool));
            dtResult.Columns.Add(
"TreeListView$Row$IsBottom"typeof(bool));
            dtResult.Columns.Add(
"TreeListView$Row$ParentRow"typeof(DataRow));
            dtResult.Columns.Add(
"TreeList$ViewRow$ClientID"typeof(string));
            RecursionOrderData(dtSource, dtResult, _rootNodeFlag, 
-1null);
            
return dtResult;
        }

        
string FormatToRowFilter(object val)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Type type 
= val.GetType();
            
if (type == typeof(string))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return string.Format("'{0}'", val.ToString().Replace("'""''"));
            }

            
else if (type == typeof(Guid))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return string.Format("'{0}'", val);
            }

            
else if (type.IsValueType)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return val.ToString();
            }

            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return string.Format("'{0}'", val.ToString().Replace("'""''"));
            }

        }

        
bool RecursionOrderData(DataTable dtSource, DataTable dtResult, object parentID, int depth, DataRow parentDatarow)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            DataView dv 
= new DataView(dtSource);
            dv.RowFilter 
= string.Format("{0}={1}", _parentKey, FormatToRowFilter(parentID));
            dv.Sort 
= _sortKey;
            DataRow dr 
= null;
            depth
++;
            
for (int i = 0; i < dv.Count; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                dr 
= dtResult.NewRow();

                
for (int j = 0; j < dv[i].Row.ItemArray.Length; j++)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    dr[j] 
= dv[i][j];
                }


                
if (i == dv.Count - 1//isBottom
ExpandedSubBlockStart.gifContractedSubBlock.gif
                {
                    dr[
"TreeListView$Row$IsBottom"= true;
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    dr[
"TreeListView$Row$IsBottom"= false;
                }

                dr[
"TreeListView$Row$Depth"= depth;
                dr[
"TreeListView$Row$ParentRow"= parentDatarow;
                
if (depth == 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    dr[
"TreeList$ViewRow$ClientID"= Guid.NewGuid().ToString();
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    dr[
"TreeList$ViewRow$ClientID"= parentDatarow["TreeList$ViewRow$ClientID"].ToString() + "/" + Guid.NewGuid().ToString();
                }


                dtResult.Rows.Add(dr);
                dr[
"TreeListView$Row$IsLeaf"= !RecursionOrderData(dtSource, dtResult, dv[i][_columnKey], depth, dr);
            }


            
return dv.Count > 0;
        }


        
public override bool AllowPaging
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return base.AllowPaging;
            }

            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
base.AllowPaging = false;
            }

        }


        
public override bool AutoGenerateColumns
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return base.AutoGenerateColumns;
            }

            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
base.AutoGenerateColumns = false;
            }

        }


ContractedSubBlock.gifExpandedSubBlockStart.gif        
重载:CreateRow#region 重载:CreateRow
        
protected override GridViewRow CreateRow(int rowIndex, int dataSourceIndex, DataControlRowType rowType, DataControlRowState rowState)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return new TreeListViewRow(rowIndex, dataSourceIndex, rowType, rowState);
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
重写:Rows#region 重写:Rows
        
private TreeListViewRowCollection _rowsCollection;
        [Browsable(
false)]
        
public new TreeListViewRowCollection Rows
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                ArrayList _rowsArray 
= new ArrayList();
                
for (int i = 0; i < base.Rows.Count; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    _rowsArray.Add((TreeListViewRow)
base.Rows[i]);
                }

                
this._rowsCollection = new TreeListViewRowCollection(_rowsArray);
                
return this._rowsCollection;
            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
重载:OnInit#region 重载:OnInit
        
protected override void OnInit(EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
base.OnInit(e);
            Page.RegisterRequiresPostBack(
this);

            
if (!Page.ClientScript.IsClientScriptIncludeRegistered("JS_TreeListView"))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
this.Page.ClientScript.RegisterClientScriptInclude(this.GetType(), "JS_TreeListView", Page.ClientScript.GetWebResourceUrl(this.GetType(), "GoldMantis.Web.UI.Resource.TreeListView.JS_TreeListView.js"));
            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
IPostBackDataHandler Members#region IPostBackDataHandler Members

        
public bool LoadPostData(string postDataKey, NameValueCollection postCollection)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return false;
        }


        
public void RaisePostDataChangedEvent()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{

        }


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
方法:RenderCheckBoxExField#region 方法:RenderCheckBoxExField
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 处理CheckBoxExField类型的列
        
/// </summary>

        private void RenderCheckBoxExField()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (!this.ShowHeader && !this.ShowFooter)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }
 

            
foreach (DataControlField field in Columns)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (field is CheckBoxExField)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
int checkBoxExFieldIndex = Columns.IndexOf(field) + this.GetAutoGenerateButtonCount();
                    
foreach (GridViewRow row in Rows)
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
{
                        
if (row.RowType == DataControlRowType.Header)
ExpandedSubBlockStart.gifContractedSubBlock.gif                        
{
                            row.Cells[checkBoxExFieldIndex].Controls.Clear();
                        }

                        
if (row.RowType == DataControlRowType.DataRow)
ExpandedSubBlockStart.gifContractedSubBlock.gif                        
{
                            row.Cells[checkBoxExFieldIndex].Controls[
0].ID = "cbChoose";
                            ((CheckBox)row.Cells[checkBoxExFieldIndex].Controls[
0]).Attributes.Add("onclick""ChooseTree(this);");
                        }

                    }


ContractedSubBlock.gifExpandedSubBlockStart.gif                    
注册脚本#region 注册脚本
                    
string script = @"
    var modifyId = """" ;
    var choosedId = """";
    var choosedIndex; 
    function ChooseTree(obj)
    {
        var cTrId = obj.parentElement.parentElement.parentElement.id;
        var treeTable = document.getElementById(""
"+this.ClientID+@""");
        for( var i = 0; i < treeTable.rows.length; i++ )
        {
            if( treeTable.rows[i].id.indexOf(cTrId) != -1 && treeTable.rows[i].id != cTrId )
            {
                document.getElementById(treeTable.rows[i].id+""_cbChoose"").checked = obj.checked;
            }
        }
        choosedId = """";
        choosedIndex = new Array();
        for( var i = 1; i < treeTable.rows.length; i++ )
        {
            if( document.getElementById(treeTable.rows[i].id+""_cbChoose"").checked )
            {
                choosedId += treeTable.rows[i].id.substring(treeTable.rows[i].id.lastIndexOf(""/"")+1) + "","";
                choosedIndex.push(i);
            }
        }
        
        choosedId = choosedId.substring(0,choosedId.length-1); 
    }
";
                    
if (!Page.ClientScript.IsStartupScriptRegistered("TreeListView_CheckBoxExField"))
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
{
                        Page.ClientScript.RegisterStartupScript(GetType(), 
"TreeListView_CheckBoxExField", script, true);
                    }

                    
#endregion

                }

            }

        }

ContractedSubBlock.gifExpandedSubBlockStart.gif        
方法:GetAutoGenerateButtonCount#region 方法:GetAutoGenerateButtonCount
        
private int GetAutoGenerateButtonCount()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
int num = 0;
            
if (this.AutoGenerateDeleteButton || this.AutoGenerateEditButton || this.AutoGenerateSelectButton)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                num 
= 1;
            }

            
return num;
        }

        
#endregion

        
#endregion


        
protected override void Render(HtmlTextWriter writer)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            RenderCheckBoxExField();
            
base.Render(writer);
        }

    }

 

 

  public   class  TreeListViewRow : GridViewRow
ExpandedBlockStart.gifContractedBlock.gif    
{
        
public TreeListViewRow(int rowIndex, int dataItemIndex, DataControlRowType rowType, DataControlRowState rowState)
            : 
base(rowIndex, dataItemIndex, rowType, rowState)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{

        }

        
        
protected override void OnPreRender(EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
base.OnPreRender(e);
            
if (this.RowType == DataControlRowType.DataRow)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (this.Parent.Parent is TreeListView)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    TreeListView treeListView 
= this.Parent.Parent as TreeListView;
                    DataRow dr 
= ((DataTable)treeListView.DataSource).Rows[this.DataItemIndex] as DataRow;
                    
string str = GetTreeNodeImg(dr, Convert.ToBoolean(dr["TreeListView$Row$IsLeaf"]), Convert.ToBoolean(dr["TreeListView$Row$IsBottom"]));
                    
this.Cells[treeListView.NodeColumnIndex].Text = str + this.Cells[treeListView.NodeColumnIndex].Text;
                    
this.ID = dr["TreeList$ViewRow$ClientID"].ToString();
                    
if (treeListView.ExpendDepth > 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
{
                        
this.Style["display"= treeListView.ExpendDepth >= Convert.ToInt32(dr["TreeListView$Row$Depth"]) ? "block" : "none";
                    }

                }

            }

            
        }


ContractedSubBlock.gifExpandedSubBlockStart.gif        
获取Tree的图片#region 获取Tree的图片
        
string GetTreeNodeImg(DataRow dr, bool isLeaf, bool isBottom)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return GetTreeNodeOtherImg(dr) + GetTreeNodeLastImg(isLeaf, isBottom);
        }

        
string GetTreeNodeOtherImg(DataRow dr)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (dr["TreeListView$Row$ParentRow"!= null&&!dr["TreeListView$Row$ParentRow"].Equals(DBNull.Value))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                DataRow drParentRow 
= dr["TreeListView$Row$ParentRow"as DataRow;
                
bool parentIsBottom = Convert.ToBoolean(drParentRow["TreeListView$Row$IsBottom"]);
                
if (parentIsBottom)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
return GetTreeNodeOtherImg(drParentRow) + string.Format("<img src={0} align=absmiddle>", TreeListView.TreeImageFolder + "white.gif");
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
return GetTreeNodeOtherImg(drParentRow) + string.Format("<img src={0} align=absmiddle>", TreeListView.TreeImageFolder + "i.gif");
                }


            }

            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return string.Empty;
            }

        }

        
string GetTreeNodeLastImg(bool isLeaf, bool isBottom)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//最后靠近的那个Image
            string lastImg = string.Empty;
            
if (isLeaf)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (isBottom)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    lastImg 
= string.Format("<img src={0} align=absmiddle>", TreeListView.TreeImageFolder + "l.gif");
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    lastImg 
= string.Format("<img src={0} align=absmiddle>",TreeListView.TreeImageFolder + "t.gif");
                }

            }

            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (isBottom)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
ExpandedSubBlockStart.gifContractedSubBlock.gif                    lastImg 
= string.Format("<img src={0} align=absmiddle οnclick='ClickNode(this,true,\"{1}\");' style=\"cursor: hand\">", TreeListView.TreeImageFolder + "lminus.gif"this.Parent.Parent.ClientID);
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
ExpandedSubBlockStart.gifContractedSubBlock.gif                    lastImg 
= string.Format("<img src={0} align=absmiddle οnclick='ClickNode(this,true,\"{1}\");' style=\"cursor: hand\">", TreeListView.TreeImageFolder + "tminus.gif"this.Parent.Parent.ClientID);
                }

            }

            
return lastImg;

        }

        
#endregion

 

Js代码实现折叠效果

 

 

ContractedBlock.gif ExpandedBlockStart.gif Code

var lExpend = "lminus.gif";
var lPinch = "lplus.gif";   
var tExpend = "tminus.gif";
var tPinch = "tplus.gif";         

function ClickNode(img,isBottom,tableId)
ExpandedBlockStart.gifContractedBlock.gif
{
    
var imgId = img.src.substring(img.src.lastIndexOf("/")+1);
    
var url = img.src.substring(0,img.src.lastIndexOf("/")+1);
    
var oldTrId = img.parentElement.parentElement.id;
    
var newTrId = oldTrId.substring(oldTrId.indexOf("_")+1);
    
    
if( isBottom)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
if( imgId == lExpend)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            img.src 
=  url+ lPinch;
            img.parentElement.id 
= lPinch;
            PinchNode(newTrId,oldTrId,tableId);
        }

        
else
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            img.src 
= url + lExpend;
            img.parentElement.id 
= lExpend;
            ExpendNode(newTrId,oldTrId,tableId);
        }
   
    }

    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
if( imgId == tExpend )
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            img.src 
=  url+ tPinch;
            img.parentElement.id 
= tPinch;
            PinchNode(newTrId,oldTrId,tableId);
      
        }

        
else
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            img.src 
= url + tExpend;
            img.parentElement.id 
= tExpend;
            ExpendNode(newTrId,oldTrId,tableId);
        }
   
    }

}


function ExpendNode(newId,oldId,tableId)
ExpandedBlockStart.gifContractedBlock.gif
{
    
var tree = document.getElementById(tableId);
    
forvar i = 0; i < tree.rows.length; i++ )
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
if( tree.rows[i].id.indexOf(newId) != -1 && tree.rows[i].id != oldId )
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
var isExpend = true;
            
var pId = tree.rows[i].id;
           
            
while( pId != oldId)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
forvar j = 0; j < 2; j++ )
                    pId 
= pId.substring( 0,pId.lastIndexOf("/"));
                
var parent = document.getElementById(pId);
                
if( parent != null )
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
var tempId = parent.cells[2].id;
                    
if( tempId == lExpend || tempId == tExpend || tempId == "")
                        ;
                    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
{
                        isExpend 
= false;
                        
break;
                    }

                }

                
else
                    
break;
            }

            
if( isExpend )
               tree.rows[i].style.display
="block";  
        }

    }

}


function PinchNode(newId,oldId,tableId)
ExpandedBlockStart.gifContractedBlock.gif
{
    
var tree = document.getElementById(tableId);
    
forvar i = 0; i < tree.rows.length; i++ )
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
if( tree.rows[i].id.indexOf(newId) != -1 && tree.rows[i].id != oldId)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            tree.rows[i].style.display 
= "none";
        }

    }

}

 

转载于:https://www.cnblogs.com/wschacker/archive/2008/07/24/1250446.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值