此例子为一工程的一个页面,通过devtreelist来展示数据表中的带上下级结构的结构,点击treelist来展示选中的treelist节点的相关子表数据。子表数据通过aspxgridview来展示,可以对子表数据进行数据维护。最后利用js来实现对子表数据的排序。
页面加载后的展示效果:
点击左边树状结构来异步实现子表相关数据展示:
点击gridview的数据操作列进行数据操作(使用覆盖效果,覆盖其他内容):
点击排序列的序号进行排序:
如果上述数据操作效果以及展示方式符合你的项目需求,那么可以尝试着看下整个页面的实现方式
引入dev的相关命名注册空间:
aspx页:
<%@ Register Assembly="DevExpress.Web.ASPxTreeList.v9.1, Version=9.1.2.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"
Namespace="DevExpress.Web.ASPxTreeList" TagPrefix="dxwtl" %>
<%@ Register Assembly="DevExpress.Web.ASPxGridView.v9.1.Export, Version=9.1.2.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"
Namespace="DevExpress.Web.ASPxGridView.Export" TagPrefix="dxwgv" %>
<%@ Register Assembly="DevExpress.Web.v9.1, Version=9.1.2.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"
Namespace="DevExpress.Web.ASPxPanel" TagPrefix="dxp" %>
<%@ Register Assembly="DevExpress.Web.v9.1, Version=9.1.2.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"
Namespace="DevExpress.Web.ASPxCallbackPanel" TagPrefix="dxcp" %>
<%@ Register Assembly="DevExpress.Web.v9.1, Version=9.1.2.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"
Namespace="DevExpress.Web.ASPxClasses" TagPrefix="dxw" %>
<%@ Register Assembly="DevExpress.Web.v9.1, Version=9.1.2.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"
Namespace="DevExpress.Web.ASPxTabControl" TagPrefix="dxtc" %>
<%@ Register Assembly="DevExpress.Web.ASPxGridView.v9.1, Version=9.1.2.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"
Namespace="DevExpress.Web.ASPxGridView" TagPrefix="dxwgv" %>
cs页面:
using DevExpress.Web.ASPxEditors;
using DevExpress.Web.ASPxTabControl;
using DevExpress.Web.ASPxTreeList;
第一步:左边组织树的实现:aspxtreelist的本质还是aspxgridview,但是在aspxtreelist的引入ParentID的概念来指定当前树节点的
上一级。例如中国(01)-北京(0101)-昌平(010106)。要用aspxtreelist来展示,那么各级的ParentID为中国(0)-北京(01)-
昌平(0101)。也就是在数据集中加入上级的ID。然后再将该程序集指定为aspxtreelist的数据源即可(当然在前台要设置ID和ParentID
对应的fieldname)。另外一种方法为一级一级的自主生成数。该实例即使用该方法。
aspx:
dxwtl:ASPxTreeList ID="devtrlstRole" Height="200px" runat="server" Cursor="default" ClientInstanceName="treelist" AutoGenerateColumns="False" Width="250px" KeyFieldName="ZXTBS" ParentFieldName="MKFLBS">
<Columns>
<dxwtl:TreeListTextColumn Caption="模块分类名称" FieldName="name" VisibleIndex="0">
</dxwtl:TreeListTextColumn>
<dxwtl:TreeListTextColumn FieldName="MKFLBS" VisibleIndex="1" Visible="False">
</dxwtl:TreeListTextColumn>
<dxwtl:TreeListTextColumn FieldName="MXMKBS" VisibleIndex="1" Visible="False">
</dxwtl:TreeListTextColumn>
</Columns>
<SettingsBehavior ExpandCollapseAction="NodeDblClick" AllowFocusedNode="True" AllowSort="False" />
<ClientSideEvents FocusedNodeChanged="function(s, e) {
onFocusChanged();
}" Init="function(s, e) {
devcbxgvwDetails.SetVisible(false);
}" />
</dxwtl:ASPxTreeList>
cs:
private void TreelistBind()
{
devtrlstRole.ClearNodes();
DataTable DTChildSys, DTModul;
SelectSQL = "select * from DVAA024";
QueryData = DataHandle.ExecuteSQL(SelectSQL);
Session["CWW_DT_XTMKJZ"] = QueryData.Tables[0];
DataView DVChildSys = QueryData.Tables[0].DefaultView;
string[] ChildSys = { "ZXTBS", "ZXTMC" };
DTChildSys = DVChildSys.ToTable(true, ChildSys);
string[] Module = { "ZXTBS", "MKFLBS", "ZXTMC", "MKFLMC" };
DTModul = DVChildSys.ToTable(true, Module);
int Count = 0;
HashDataCopiedValue = new Hashtable();
for (int i = 0; i < DTChildSys.Rows.Count; i++)
{
TreeListNode TrlstChildSys = CreateNodeCore(i + 1, DTChildSys.Rows[i]["ZXTMC"].ToString().Trim(), null);
TrlstChildSys.Expanded = true;
QueryRow = DTModul.Select("ZXTBS='" + DTChildSys.Rows[i]["ZXTBS"].ToString().Trim() + "'");
for (int j = 0; j < QueryRow.Length; j++)
{
TreeListNode TrlstModule = CreateNodeCore(DTChildSys.Rows.Count + Count + 1, QueryRow[j]["MKFLMC"].ToString().Trim(), TrlstChildSys);
HashDataCopiedValue[DTChildSys.Rows.Count + Count + 1] = QueryRow[j]["MKFLBS"].ToString().Trim();
Count++;
}
}
Session["CWW_Hash"] = HashDataCopiedValue;
}
TreeListNode CreateNodeCore(object key, string name, TreeListNode parentNode)
{
TreeListNode node = devtrlstRole.AppendNode(key, parentNode);
node["name"] = name;
return node;
}
这样我们就实现了aspxtreelist的数据装载,其中需要注意我们在前台页设置了以下属性以及参数来进行下一步的效果实现
1.AllowFocusedNode="True",设置树为可聚焦,主要实现通过聚焦来展示子表数据。
2.编写了两个客户端事件来实现展示子表数据以及相关样式设置也就是 <ClientSideEvents FocusedNodeChanged="function(s, e) {
onFocusChanged(); }" Init="function(s, e) {devcbxgvwDetails.SetVisible(false);}" />
其中OnFoucsChanged对应的js如下:
<script type="text/javascript" language="javascript">
function onFocusChanged(){
var key=treelist.GetFocusedNodeKey();
devcbxgvwDetails.PerformCallback(key);
}
</script>
通过该脚本来通知aspxgridview按照选中的treelist的主键值来进行相应数据的回发。
第二步,通过编写的js脚本中的performcallback方法捎带的参数来进行aspxgridview子表数据的更新,更新通过aspxgridview的customcallback
来实现。
aspx:
CS页面CustomCallback接受参数进行异步刷新:
protected void devcbxgvwDetails_CustomCallback(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomCallbackEventArgs e)
{
Hashtable HT = (Hashtable)Session["CWW_Hash"];
string parm = e.Parameters.Trim();
if (parm.Contains(","))
{
string[] parm2 = e.Parameters.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
DataTable DT = (DataTable)Session["CWW_DT_XTMKMX"];
for (int i = 0; i < parm2.Length; i++)
{
DataRow UpdRow = DT.Select("MXMKMC='" + parm2[i].Trim() + "'")[0];
string strUpdSQL = "update DBAA024 set MXMKPX='" + (i + 1).ToString() + "' where MXMKBS='" + UpdRow["MXMKBS"].ToString().Trim() + "'";
DataHandle.ExecuteCommand(strUpdSQL);
UpdRow.BeginEdit();
UpdRow["MXMKPX"] = (i + 1).ToString();
UpdRow.EndEdit();
DT.AcceptChanges();
}
SelectSQL = "select * from DVAA024";
QueryData = DataHandle.ExecuteSQL(SelectSQL);
Session["CWW_DT_XTMKJZ"] = QueryData.Tables[0];
devcbxgvwDetails.DataSource = DT.DefaultView;
devcbxgvwDetails.DataBind();
Session["CWW_DT_XTMKMX"] = DT;
}
else
{
bool ismkfl = false;
foreach (DictionaryEntry di in HT)
{
if (di.Key.ToString() == parm)
{
ismkfl = true;
break;
}
}
devcbxgvwDetails.JSProperties["cp_key"] = true;
if (!ismkfl)
{
devcbxgvwDetails.JSProperties["cp_key"] = false;
return;
}
string keyvalue = HT[int.Parse(parm)].ToString();
QueryTable = (DataTable)Session["CWW_DT_XTMKJZ"];
QueryRow = QueryTable.Select("MKFLBS='" + keyvalue + "'");
SelectSQL = "select MKFLBS,MXMKBS,MXMKMC,MXMKPX,MKTXSJ from DVAA024 where 1<>1";
DataTable DT = DataHandle.ExecuteSQL(SelectSQL).Tables[0];
for (int i = 0; i < QueryRow.Length; i++)
{
DataRow DR = DT.NewRow();
DR["MKFLBS"] = parm;
DR["MXMKBS"] = QueryRow[i]["MXMKBS"].ToString().Trim();
DR["MXMKPX"] = QueryRow[i]["MXMKPX"].ToString().Trim();
DR["MXMKMC"] = QueryRow[i]["MXMKMC"].ToString().Trim();
DR["MKTXSJ"] = QueryRow[i]["MKTXSJ"].ToString().Trim();
DT.Rows.Add(DR);
DT.AcceptChanges();
}
devcbxgvwDetails.DataSource = DT.DefaultView;
devcbxgvwDetails.DataBind();
Session["CWW_DT_XTMKMX"] = DT;
}
}
其中为什么出现传过来的值进行了次是否包含逗号的判断,在最后再说明。
到此我们实现了aspxgridview跟随选择的treelist节点不同的异步更新。
第三步:aspxgridview自身的相关操作,主要有数据更新,删除,新建,克隆,分页,点击表头排序等功能
protected void devcbxgvwDetails_CustomButtonCallback(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomButtonCallbackEventArgs e)
{
if (e.ButtonID != "Copy2")
{ return; }
HashDataField = new Hashtable();
foreach (string strField in HashDataField)
{
HashDataField[strField] = devcbxgvwDetails.GetRowValues(e.VisibleIndex, strField);
}
devcbxgvwDetails.AddNewRow();
}
protected void devcbxgvwDetails_CustomErrorText(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomErrorTextEventArgs e)
{
if (Session["CWW_SJXMS_Err"] != null)
{
e.ErrorText = Session["CWW_SJXMS_Err"].ToString().Trim();
}
else
{
e.ErrorText = "更新失败,请确保更新合法或者更新不重复";
}
}
protected void devcbxgvwDetails_BeforeColumnSortingGrouping(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewBeforeColumnGroupingSortingEventArgs e)
{
DataTable DT = (DataTable)Session["CWW_DT_XTMKMX"];
devcbxgvwDetails.DataSource = DT.DefaultView;
}
protected void devcbxgvwDetails_HtmlEditFormCreated(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewEditFormEventArgs e)
{
DataTable DT = (DataTable)Session["CWW_DT_XTMKMX"];
TextBox txtOrder = (TextBox)devcbxgvwDetails.FindEditFormTemplateControl("txtOrder");
ASPxComboBox devcbxSelLogo = (ASPxComboBox)devcbxgvwDetails.FindEditFormTemplateControl("devcbxSelLogo");
if (txtOrder.Text.Trim() == string.Empty)
{
txtOrder.Text = (DT.Rows.Count + 1).ToString();
}
if (devcbxSelLogo.SelectedIndex == -1)
{
devcbxSelLogo.SelectedIndex = 0;
}
}
protected void devcbxgvwDetails_PageIndexChanged(object sender, EventArgs e)
{
if (Session["CWW_DT_XTMKMX"] != null)
{
DataTable DT = (DataTable)Session["CWW_DT_XTMKMX"];
devcbxgvwDetails.DataSource = DT.DefaultView;
devcbxgvwDetails.DataBind();
}
}
protected void devcbxgvwDetails_InitNewRow(object sender, DevExpress.Web.Data.ASPxDataInitNewRowEventArgs e)
{
if (HashDataField == null) return;
foreach (string strField in HashDataField)
{
e.NewValues[strField] = HashDataField[strField];
}
}
protected void devcbxgvwDetails_RowDeleting(object sender, DevExpress.Web.Data.ASPxDataDeletingEventArgs e)
{
string strDelSQL = "delete from DBAA024 where MXMKBS='" + e.Keys[0].ToString().Trim() + "'";
DataHandle.ExecuteCommand(strDelSQL);
devcbxgvwDetails.CancelEdit();
e.Cancel = true;
DataTable DT = (DataTable)Session["CWW_DT_XTMKMX"];
DataRow DR = DT.Select("MXMKBS='" + e.Keys[0].ToString().Trim() + "'")[0];
DT.Rows.Remove(DR);
DT.AcceptChanges();
Session["CWW_DT_XTMKMX"] = DT;
devcbxgvwDetails.DataSource = DT.DefaultView;
devcbxgvwDetails.DataBind();
SelectSQL = "select * from DVAA024";
QueryData = DataHandle.ExecuteSQL(SelectSQL);
Session["CWW_DT_XTMKJZ"] = QueryData.Tables[0];
}
protected void devcbxgvwDetails_RowInserting(object sender, DevExpress.Web.Data.ASPxDataInsertingEventArgs e)
{
if (Session["CWW_DT_XTMKMX"] != null)
{
DataTable DT = (DataTable)Session["CWW_DT_XTMKMX"];
DataTable DTAll = (DataTable)Session["CWW_DT_XTMKJZ"];
TextBox txtOrder = (TextBox)devcbxgvwDetails.FindEditFormTemplateControl("txtOrder");
ASPxComboBox devcbxSelLogo = (ASPxComboBox)devcbxgvwDetails.FindEditFormTemplateControl("devcbxSelLogo");
TextBox txtFeatures = (TextBox)devcbxgvwDetails.FindEditFormTemplateControl("txtFeatures");
DataRow[] DR = DTAll.Select("MXMKBS='" + devcbxSelLogo.SelectedItem.Value.ToString() + "'");
if (DR.Length > 0)
{
Session["CWW_SJXMS_Err"] = "该明细模块已经分配分类";
return;
}
if (txtOrder.Text.Trim() == string.Empty)
{
Session["CWW_SJXMS_Err"] = "字段排序不允许为空";
return;
}
if (!IsNumeric(txtOrder.Text.Trim()))
{
Session["CWW_SJXMS_Err"] = "字段排序必须为数字";
return;
}
try
{
InsertSQL = "insert into DBAA024 (MKFLBS,MXMKBS,MXMKPX,MKTXSJ) values ('" + DT.Rows[0]["MKLFBS"].ToString().Trim() + "',";
InsertSQL += "'" + devcbxSelLogo.SelectedItem.Value.ToString() + "','" + txtOrder.Text.Trim() + "',";
InsertSQL += "'" + txtFeatures.Text.Trim() + "')";
DataHandle.ExecuteCommand(InsertSQL);
devcbxgvwDetails.CancelEdit();
e.Cancel = true;
DataRow SelfRow = DT.NewRow();
SelfRow["MKFLBS"] = DT.Rows[0]["MKFLBS"].ToString().Trim();
SelfRow["MXMKBS"] = devcbxSelLogo.SelectedItem.Value.ToString();
SelfRow["MXMKPX"] = txtOrder.Text.Trim();
SelfRow["MKTXSJ"] = txtFeatures.Text.Trim();
SelfRow["MXMKMC"] = devcbxSelLogo.Text.Trim();
DT.Rows.Add(SelfRow);
DT.AcceptChanges();
Session["CWW_DT_XTMKMX"] = DT;
devcbxgvwDetails.DataSource = DT.DefaultView;
devcbxgvwDetails.DataBind();
SelectSQL = "select * from DVAA024";
QueryData = DataHandle.ExecuteSQL(SelectSQL);
Session["CWW_DT_XTMKJZ"] = QueryData.Tables[0];
}
catch
{
throw new Exception("更新失败");
}
}
}
protected void devcbxgvwDetails_RowUpdating(object sender, DevExpress.Web.Data.ASPxDataUpdatingEventArgs e)
{
if (Session["CWW_DT_XTMKMX"] != null)
{
DataTable DT = (DataTable)Session["CWW_DT_XTMKMX"];
DataTable DTAll = (DataTable)Session["CWW_DT_XTMKJZ"];
TextBox txtOrder = (TextBox)devcbxgvwDetails.FindEditFormTemplateControl("txtOrder");
ASPxComboBox devcbxSelLogo = (ASPxComboBox)devcbxgvwDetails.FindEditFormTemplateControl("devcbxSelLogo");
TextBox txtFeatures = (TextBox)devcbxgvwDetails.FindEditFormTemplateControl("txtFeatures");
if (devcbxSelLogo.SelectedItem.Value.ToString() != Session["CWW_MXMKGS_Keyvalue"].ToString())
{
DataRow[] DR = DTAll.Select("MXMKBS='" + devcbxSelLogo.SelectedItem.Value.ToString() + "'");
if (DR.Length > 0)
{
Session["CWW_SJXMS_Err"] = "该明细模块已经分配分类";
return;
}
}
if (txtOrder.Text.Trim() == string.Empty)
{
Session["CWW_SJXMS_Err"] = "字段排序不允许为空";
return;
}
if (!IsNumeric(txtOrder.Text.Trim()))
{
Session["CWW_SJXMS_Err"] = "字段排序必须为数字";
return;
}
try
{
UpdateSQL = "update DBAA024 set MXMKBS='" + devcbxSelLogo.SelectedItem.Value.ToString() + "',MXMKPX='" + txtOrder.Text.Trim() + "'";
UpdateSQL += ",MKTXSJ='" + txtFeatures.Text.Trim() + "' where MXMKBS='" + Session["CWW_MXMKGS_Keyvalue"].ToString() + "'";
DataHandle.ExecuteCommand(UpdateSQL);
devcbxgvwDetails.CancelEdit();
e.Cancel = true;
DataRow SelfRow = DT.Select("MXMKBS='" + Session["CWW_MXMKGS_Keyvalue"] + "'")[0];
SelfRow.BeginEdit();
SelfRow["MXMKBS"] = devcbxSelLogo.SelectedItem.Value.ToString();
SelfRow["MXMKPX"] = txtOrder.Text.Trim();
SelfRow["MKTXSJ"] = txtFeatures.Text.Trim();
SelfRow["MXMKMC"] = devcbxSelLogo.Text.Trim();
SelfRow.EndEdit();
DT.AcceptChanges();
Session["CWW_DT_XTMKMX"] = DT;
devcbxgvwDetails.DataSource = DT.DefaultView;
devcbxgvwDetails.DataBind();
SelectSQL = "select * from DVAA024";
QueryData = DataHandle.ExecuteSQL(SelectSQL);
Session["CWW_DT_XTMKJZ"] = QueryData.Tables[0];
}
catch
{
throw new Exception("更新失败");
}
}
}
protected void devcbxgvwDetails_StartRowEditing(object sender, DevExpress.Web.Data.ASPxStartRowEditingEventArgs e)
{
Session["CWW_MXMKGS_Keyvalue"] = e.EditingKeyValue.ToString();
}
我们为了实现在点击排序列的时候弹出一个层来,来进行排序,编写一js
function OnOrderClick(element) {
devpopupcOrder.ShowAtElement(element);
devcbpnlOrder.PerformCallback();
}
第四步:通过点击排序弹出的对话框我们进行排序,并且在点击更新后,我们需要将aspxgridview进行更新,于是我们在刚刚的
customcallback事件中进行了区分,来区分gridview的更新时来来自treelist还是来自排序。对于排序时用Js来实现的
// JScript 文件
function MoveUP()
{
var fElement=document.getElementById('devpopupcOrder$devcbpnlOrder$lstOrder');
if (fElement.options.length == 0 || fElement.options[0].selected) return;
for (var i = 1; i < fElement.options.length; i++)
{
if (fElement.options[i].selected)
{
var text = fElement.options[i].text;
var value = fElement.options[i].value;
var selected = fElement.options[i].selected;
fElement.options[i].text = fElement.options[i - 1].text;
fElement.options[i].value = fElement.options[i - 1].value;
fElement.options[i].selected = fElement.options[i - 1].selected;
fElement.options[i - 1].text = text;
fElement.options[i - 1].value = value;
fElement.options[i - 1].selected = selected;
}
}
}
function MoveDown()
{
var fElement=document.getElementById('devpopupcOrder$devcbpnlOrder$lstOrder');
if (fElement.options.length == 0 || fElement.options[fElement.options.length - 1].selected) return;
for (var i = fElement.options.length - 1; i > -1; i--)
{
if (fElement.options[i].selected)
{
var text = fElement.options[i + 1].text;
var value = fElement.options[i + 1].value;
var selected = fElement.options[i + 1].selected;
fElement.options[i + 1].text = fElement.options[i].text;
fElement.options[i + 1].value = fElement.options[i].value;
fElement.options[i + 1].selected = fElement.options[i].selected;
fElement.options[i].text = text;
fElement.options[i].value = value;
fElement.options[i].selected = selected;
}
}
}
function ToggleSaveSortlist(){
var fElement=document.getElementById('devpopupcOrder$devcbpnlOrder$lstOrder');
var list='';
for(var i=0;i<fElement.options.length;i++){
list+=fElement.options[i].text+',';
}
devpopupcOrder.Hide();
devgvwDataInfo.PerformCallback(list);
}
function ToggleSaveSortlist2(){
var fElement=document.getElementById('devpopupcOrder$devcbpnlOrder$lstOrder');
var list='';
for(var i=0;i<fElement.options.length;i++){
list+=fElement.options[i].text+',';
}
devpopupcOrder.Hide();
devgvwData.PerformCallback(list);
}
function ToggleSaveSortlist3(){
var fElement=document.getElementById('devpopupcOrder$devcbpnlOrder$lstOrder');
var list='';
for(var i=0;i<fElement.options.length;i++){
list+=fElement.options[i].text+',';
}
devpopupcOrder.Hide();
devgvwDefault.PerformCallback(list);
}
function ToggleSaveSortlist4(){
var fElement=document.getElementById('devpopupcOrder$devcbpnlOrder$lstOrder');
var list='';
for(var i=0;i<fElement.options.length;i++){
list+=fElement.options[i].text+',';
}
devpopupcOrder.Hide();
devcbxgvwDetails.PerformCallback(list);
}