真正類似於 Excel 的網格控制項

來源:互聯網
上載者:User
excel|控制項 注 與本文相關的下載檔案的 Visual Basic_ 版本已於 3 月 4 日進行了更新。如果您是在 3 月 4 日之前下載原始碼的,則將需要重新下載該檔案以獲得 Visual Basic 檔案。



ASP.NET DataGrid 控制項產生一個 HTML 輸出結果,此結果看上去確實像 Microsoft Excel 工作表的 Web 副本。另外,該控制項支援如選擇和就地編輯之類的功能,這些功能又進一步證實了這種相似性。特別是,從支援就地編輯功能這一點來看時,這種相似性就最為明顯了。當您單擊特殊類型的命令列時,網格會使用文字框(而非靜態文本)重繪其內容。與此同時,命令列會更改布局,將編輯連結替換為兩個其他連結 — 一個用來儲存所做的更改,另一個用來取消所做的更改。整個看上去幾乎與 Excel 名稱框命令欄完全相同。

DataGrid 還使程式員有機會在某種程度上自訂所編輯的儲存格的布局。這可通過以下方法來實現:使用模板化列來代替繫結資料行和按鈕列,並在模板化列的標記本文中定義編輯模板。

簡單地說,DataGrid 控制項只是為就地編輯提供基礎結構,並在儲存所做的更改時激發某些事件。為了能夠完全編輯,網格組件應當提供三個您可能希望針對資料來源執行的基本操作:“插入、“刪除和 “更新”。DataGrid 用於編輯的基礎結構(基本上是 EditCommandColumn 列類)只保證能夠執行更新和刪除操作。實現 “刪除” 功能相對容易些,而且只要求您定義一個命令名為 “刪除” 的 ButtonColumn 對象,並等待DeleteCommand 事件激發。

在本專欄中,您將看到如何擴充 DataGrid 控制項,使其支援 INSERT 命令。我們將通過建立一個新類並讓其從 DataGrid 繼承來實現這一點。我們將使該類儘可能多地實現樣本代碼,以省去某些重複編碼。因此,我們將擁有一個激發新事件和更具體事件的控制項,而且我們可以使用這個唯一的介面來維護資料庫表。

EditableGrid 控制項

新控制項應當具有哪種介面?

的思路是儘可能限制程式員必須編寫的代碼的數量。該控制項將負責向其自身的介面中添加任何新行,然後在需要儲存所做的更改時警告使用者。這一原則適用於大多數操作,而不應當僅限於 “插入”。在實現就地編輯和刪除時,總是必須在 SQL 陳述式周圍放一些相對標準的和重複的代碼。特別是在實現就地編輯功能時,必須重設所編輯項目的索引,並重新載入和重新綁定更新過的資料來源。所有這些樣本代碼將嵌入到新的 EditableGrid 控制項中。因此,該控制項提供一個名為 AddNewRow 的新布爾屬性,以及幾個自訂事件 — InitRow、UpdateView、“儲存資料”、“插入資料” 和 “刪除資料”。

當使用者希望添加新行時,他(或她)只需將 AddNewRow 屬性設定為 true 並重新綁定該控制項。該操作的其餘部分在內部發生。(稍後我將描述此過程的細節。)新行將在編輯模式下繪製,InitRow 事件將激發,其目的只是使您有機會將某些欄位設定為預設值。

UpdateView 的角色不與更新操作緊密相關。DataGrid 控制項不快取資料源,因此,無論頁面何時回傳(以便進行分頁、排序、編輯、插入或刪除),您都需要重新綁定。為了簡化編碼並儘可能多地嵌入編碼,添加了這個新事件。當該網格需要設定其 DataSource 屬性時,“更新視圖” 就會激發。“更新視圖” 的典型處理常式將當前的資料來源分配給該屬性並調用 DataBind 方法。

當相應的 SQL 陳述式不能進一步順延強制時,就會激發其他三個事件 — “儲存資料”、“插入資料” 和 “刪除資料”。在處理其中的任何事件時,可設定和執行 “更新”、“插入” 或 “刪除” 語句。您負責檢索更新後的資料,並準備和執行該命令。除了 “插入資料”(與 DataGrid 編程介面沒有緊密關係)以外,“儲存資料” 和 “刪除資料” 也不同於標準的 UpdateCommand 和 DeleteCommand,這是因為它們更具體而且只要求您執行 SQL 代碼。新事件基本上由 UpdateCommand 和 DeleteCommand 的處理常式激發,這些處理常式是 EditableGrid 控制項在載入時以靜默方式定義的。這些內部處理常式負責執行所有其他任務(例如,重設索引)並重新整理視圖。後者(即重新整理視圖)是通過激發 UpdateView 事件來完成的。

設定控制項

讓我們快速探索 EditableGrid 類。該類的建構函式初始化某些公用屬性和受保護的屬性,並為基類的幾個事件設定預設處理常式。

namespace BWSLib
{
public class EditableGrid : DataGrid
{
public EditableGrid()
{
AllowFullEditing = true;
AddNewRow = false;
AllowPaging = true;
RejectChanges = false; // internal use
MustInsertRow = false; // internal use

// Handlers
Init += new EventHandler(OnInit);
PageIndexChanged += new
DataGridPageChangedEventHandler(OnPageIndexChanged);
ItemCreated += new DataGridItemEventHandler(OnItemCreated);
CancelCommand += new DataGridCommandEventHandler(OnCancelCommand);
EditCommand += new DataGridCommandEventHandler(OnEditCommand);
UpdateCommand += new DataGridCommandEventHandler(OnUpdateCommand);
DeleteCommand += new DataGridCommandEventHandler(OnDeleteCommand);
}
:
}
}

EditableGrid 類有一個尚未提到的公用屬性 — AllowFullEditing。該屬性成員支援對網格的完全編輯功能。如果您將該屬性設定為 false,則該控制項將不提供就地編輯或插入功能。究竟執行的是怎樣的處理?該控制項自動將 AllowPaging 設定為 true,並為 PageIndexChanged 提供一個處理常式。這意味著 EditableGrid 還是比 DataGrid 控制項好一些,因為它為您提供自動的空閑分頁。

當 AllowFullEditing 設定為 true(預設值)時,EditableGrid 控制項自動將兩個新列追加到網格中。第一列是 EditCommandColumn,它提供就地編輯功能。第二列是 ButtonColumn,它的命令是 DELETE。這兩列都是通過為響應 Init 事件而啟動並執行處理常式來添加的。

public void OnInit(Object sender, EventArgs e)
{
if (AllowFullEditing)
AddWorkerColumns();
}

private void AddWorkerColumns()
{
// Edit column
EditCommandColumn editColumn = new EditCommandColumn();
editColumn.EditText = EditColumnText;
editColumn.UpdateText = EditColumnUpdateText;
editColumn.CancelText = EditColumnCancelText;
Columns.Add(editColumn);

// Delete column
ButtonColumn deleteColumn = new ButtonColumn();
deleteColumn.CommandName = "delete";
deleteColumn.Text = DeleteColumnText;
Columns.Add(deleteColumn);
}

EditColumnText、EditColumnUpdateText、EditColumnCancelText 和 DeleteColumnText 確定用來觸發編輯和刪除操作的按鈕的文本。它們在預設時分別為 “編輯”、“確定”、“取消” 和 “刪除”。

在將該控制項插入到任何 ASP.NET 頁中之前,必須按如下方式註冊它:

<%@Register TagPrefix="expo" Namespace="BWSLib" Assembly="EditableGrid" %>

在上面的聲明中,可以更改 TagPrefix 屬性的內容,但是,除了該控制項的命名空間和類名可以修改以外,不能更改任何其他內容。下面的代碼顯示如何在 ASPX 頁中聲明該控制項:

<expo:EditableGrid id="grid" runat="server"
AutoGenerateColumns="false"
Font-Name="verdana" Font-Size="xx-small"
CellSpacing="0" CellPadding="3"
BorderStyle="solid" BorderColor="skyblue" BorderWidth="1"
GridLines="both"
PageSize="4"
DataKeyField="employeeid"

OnInitRow="InitRow"
OnUpdateView="UpdateView"
OnSaveData="SaveData"
OnInsertData="InsertData"
OnDeleteData="DeleteData">
:
<columns>
:
</columns>
</expo:EditableGrid>
樣本頁從一個名為 Employees 的 Microsoft Access 2000 表讀出資料並將產生的 DataSet(資料集)儲存在 Cache 對象中。

private DataSet PhysicalDataRead()
{
OleDbDataAdapter da = new OleDbDataAdapter(
"SELECT * FROM Employees",
"PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=c:\\myemployees.mdb;");
DataSet ds = new DataSet();
da.Fill(ds, "Employees");
return ds;
}

圖 1 顯示該頁中控制項的輸出結果。



圖 1. 操作中的 EditableGrid 控制項

添加和刪除列時無需任何額外的代碼。可是,必須要指定 UpdateView 處理常式。但是,正如您可以看到的那樣,這是一段必須在多個位置與 DataGrid 控制項一起使用的代碼。然而,由於有 UpdateView 事件,所以只需指定一次。

public void UpdateView(Object sender, EventArgs e)
{
UpdateDataView();
}
private void UpdateDataView()
{
DataSet ds = (DataSet) Cache["MyData"];
DataView dv = ds.Tables["Employees"].DefaultView;
grid.DataSource = dv;
grid.DataBind();
}

在上面的控制項聲明中,還可以看到三個與資料相關的事件的事件處理常式。讓我們看一下該控制項如何處理它們。

Insert 操作

EditableGrid 控制項不包括任何用來啟動 “插入” 操作的使用者介面元素。正如對於其他重要功能一樣,程式員負責將能夠觸發網格上給定事件的超級連結或按鈕放到頁面中。由於添加新項目不是依賴特定行的操作,因此建議您不要使用特殊的命令列(例如,“編輯” 或 “刪除”)。用戶端代碼處理頁面級事件,並設定 AddNewRow 屬性以響應該操作。接著,頁面重新整理網格,以反映所做的更改。例如,圖 1 中的 Insert(插入)按鈕連結到下面的 on-click 處理常式:

public void OnInsert(Object sender, EventArgs e)
{
grid.AddNewRow = true;
UpdateDataView();
}

“更新資料檢視” 是頁面級過程,它處理網格資料繫結並設定 “資料來源” 屬性。

設計的思路是使使用者不直接將新記錄添加到資料來源中,而是只聲明其想要實現的目標。因此,在設定 EditableGrid 控制項的 “資料來源” 屬性時,該控制項會檢查 AddNewRow 的值。在派生的控制項中,因為有多種訪問器,所以可以很方便地確定何時讀取或寫入給定屬性。這樣做之後,EditableGrid 會按如下方式重寫 “資料來源” 屬性:

public override object DataSource
{
get {return base.DataSource;}
set
{
// Standard behavior
base.DataSource = value;

// Customized behavior
if (AllowFullEditing)
{
if (AddNewRow)
{
AddNewRow = false;
InsertNewRow();
}

// More code here...
:
}
}
}

在設定 “資料來源” 時,只要 AddNewRow 屬性為 true,就會追加一個新行。InsertNewRow 就是用來為插入和行編輯功能設定網格的內部過程。此處進行的重要假設就是網格與 “資料檢視” 對象綁定。利用該代碼,您可以方便地推廣到更普遍的解決方案。

private void InsertNewRow()
{
// Get the underlying DataTable object
DataTable dt = ((DataView) DataSource).Table;

// If any pending changes, stop here to avoid inserting over
// and over again if user refreshes...
DataTable tableOfPendingChanges = dt.GetChanges(DataRowState.Added);
if (tableOfPendingChanges!= null)
return;

// Add the new row
DataRow row = dt.NewRow();
dt.Rows.Add(row);

// Initialize the row (fire the InitRow event)
DataGridInitRowEventArgs dgire = new DataGridInitRowEventArgs();
dgire.Row = row;
OnInitRow(dgire);

// Goto to last page and turn edit mode for the last item
int nNewItemIndex = SetIndexesToLastPage(dt);
EditItemIndex = nNewItemIndex;

// Tracks that a new row has just been added (internal member)
MustInsertRow = true; // means the table has pending changes
}
在建立基礎 “資料表” 對象以後,使用 NewRow 方法添加新行,並激發自訂的 InitRow 事件,以便使用者有機會將某些欄位設定為預設值。為了實現其目標,InitRow 需要將某些資料向下傳遞到事件處理常式並接收任何更新。必須安排一個自訂的事件數目據結構和一個自訂的事件處理常式簽名。DataGridInitRowEventArgs 是事件數目據結構的名稱,而 DataGridInitRowEventHandler 是要使用的委託。

public delegate void DataGridInitRowEventHandler(
Object sender, DataGridInitRowEventArgs e);
public event DataGridInitRowEventHandler InitRow;
private void OnInitRow(DataGridInitRowEventArgs e)
{
if (InitRow != null)
InitRow(this, e);
}

DataGridInitRowEventArgs 類繼承於 EventArgs 並通過簡單地添加一個 DataRow 成員進行擴充。

public sealed class DataGridInitRowEventArgs : EventArgs
{
// Represents the row being added. You can use this object
// to set fields to default values.
public DataRow Row;
}

在激發 InitRow 事件之前,該控制項用新建立(但仍為空白)的 DataRow 對象的即時執行個體填充 Row 成員。

DataGridInitRowEventArgs dgire = new DataGridInitRowEventArgs();
dgire.Row = row;
OnInitRow(dgire);

如果需要設定某些預設值,則可以編寫 InitRow 處理常式並設定 DataRow 對象的欄位。

public void InitRow(Object sender, DataGridInitRowEventArgs e)
{
e.Row["LastName"] = "Esposito";
}

此處,DataSource 額外有一行可類比新記錄的插入操作。該行已經添加到資料來源的底部。因此,您應當使網格指向它的最後一頁,而且還要考慮到新行進入新頁的可能性。例如,如果表中有八個記錄,而且您使用的頁面大小為四,則在添加新記錄時還需要增加一個新頁。為了使使用者能夠編輯新行的內容,只需將 DataGrid 的 EditItemIndex 屬性設定為新行的頁索引。InsertNewRow 完成的最後一步是設定內部資料成員,來跟蹤向表中添加新的未提交行的操作。

簡言之,該代碼將一個空行對象添加到網格的資料來源中。該行代表 “資料表” 對象的待定更改,而且如果使用者取消該操作,則必須拒絕該行。如果使用者移到另一頁或者決定單擊和編輯同一頁上的另一行,也必須拒絕該行。拒絕待定更改是內建處理常式(例如,PageIndexChanged、EditCommand 和 CancelCommand)通過內部資料成員 RejectChanges 完成的事情之一。(有關更多詳細資料,請參閱原始碼。)

通過將新行置於編輯模式,即可完成插入階段,從而進入更新階段,如下圖所示。



圖 2. 插入新行

對於 InsertNewRow 的主體,我還需要闡明另外一個方面。在擷取資料來源之後,該方法立即確保沒有已添加但尚未提交的行。在設計上,最多可以有一個待定更改,而且如果該代碼重新進入有一個已添加的行的過程,那是由於使用者重新整理了該頁面。為了避免反覆添加空白行和未提交的行,程式流會跳出代碼塊。

Update 操作

請注意,在圖 2 中看不到可在圖 1 中看到的 Delete 列。為了簡化介面,我決定在任何行進入編輯模式時隱藏 Delete 列。並且因為有了以前提到的內建事件處理常式,所以此行為在 EditableGrid 類中是硬式編碼。

update 操作是由以下三個事件執行的:

• EditCommand — 開始該操作並以編輯模式呈現行

• UpdateCommand — 儲存所做的更改並還原預設使用者介面

• CancelCommand — 取消所做的更改並還原以前的使用者介面


用於 EditCommand 和 CancelCommand 的典型代碼是能夠方便地嵌入類中的傳統 vanilla 代碼。一般來說,此處沒有真正需要在頁面級解決的內容,但是有時情況也可能與您的特定執行個體有所不同。

“更新” 操作的應用程式特定的邏輯集中在 “更新命令” 事件中。除了儲存任何更改以外,您應當還原網格的一致狀態(取消編輯模式、還原 Delete 列和拒絕待定的更改),並確保所做的更改隨後由用於顯示的資料來源反映出來。如果您像本例中那樣使用快取資料,則後面的一點至關重要。

public void OnUpdateCommand(Object sender, DataGridCommandEventArgs e)
{
// Clear edit mode
EditItemIndex = -1;

// Show/Hide DELETE column
ToggleDeleteColumn(true);

// Reject changes on the last row
RejectChanges = true; // internal member

// Update or insert data
if (MustInsertRow) // internal member
OnInsertData(e);
else
OnSaveData(e);

// Refresh view
OnUpdateView(EventArgs.Empty);
}
UpdateCommand 處理常式取消當前行的編輯模式,然後開啟 Delete 列的可見度標誌。此時,該表可能有一個待定的更改。因為 “更新命令” 事件會在兩種情況(打算將所做的更改儲存到現有的行中時;要插入新行時)下激發,所以條件表單很有意義。內部成員 MustInsertRow 由 InsertNewRow 設定並由 DataSource 重設,它有助於確定是哪種情況。當代碼處理完網格的狀態之後,它激發兩個連續事件 — 一個事件讓頁面儲存或插入到物理資料來源中,另一個事件重新整理資料繫結。這就解釋了為何 InsertData 和 SaveData 處理常式只能執行主要通過 SQL 陳述式來進行的物理更新。

InsertData 和 SaveData 事件處理常式的簽名與 UpdateCommand 的相同。

public event DataGridCommandEventHandler SaveData;
protected virtual void OnSaveData(DataGridCommandEventArgs e)
{
if (SaveData != null)
SaveData(this, e);
}

public event DataGridCommandEventHandler InsertData;
protected virtual void OnInsertData(DataGridCommandEventArgs e)
{
if (InsertData != null)
InsertData(this, e);
}

在本文中討論的範例程式碼中,設定了幾個假設,其中一個就是假設網格的資料來源是 “資料檢視” 對象。這間接表示不支援自訂分頁,或者,更確切地講,必須仔細修改此代碼才能處理這樣的網格。這同樣適用於排序。

所作的第二個重要假設是有關使用 SQL 陳述式進行更新的。

設計思路是,無論進行了什麼樣的更改,總是激發單個 SQL 陳述式以應用它。此處設計的 EditableGrid 不能正確地處理批更新。順便提一句,在我的 Building Web Solutions with ASP.NET and ADO.NET 一書中,在介紹就地編輯時,更詳細地討論了對於網格使用批更新的優缺點。然而,如果您對使用批更新技術感興趣,請給我寄送電子郵件,我將在以後的專欄中介紹此主題。

由於您通過直接的 SQL 陳述式(或者資料來源識別為直接語句的內容)進行更新,因此,“更新命令” 事件可以成功地命令拒絕任何更改。這就是批更新方案中的主要區別。

“儲存資料” 和 “插入資料” 事件代表執行更新所必需的任務的子集。在執行該命令之後,這些處理常式必須確保網格可以訪問和顯示重新整理資料。在這種情況下,必須更新資料的快取複本。根據基礎資料庫結構描述(任何觸發器或任何自動編號的欄位),可以決定是完全重新讀取還是基於每個欄位更新快取資料。

讓我們花些時間來瞭解如何從網格的編輯模板來檢索更新後的資料。我考慮使 EditableGrid 控制項具有足夠的智能,以便從儲存格提取值,並將它們填充到 DataRow 對象中以充當事件數目據。這個方法使得在批方案中更新代碼變得微不足道。之所以決定讓 ASP.NET 頁負責提取資料,是因為這樣您也可以透明地支援編輯模板。下面我將向您展示在不使用任何特殊模板時所必需的代碼。

public void SaveData(Object sender, DataGridCommandEventArgs e)
{
StringBuilder sb = new StringBuilder("");
sb.Append("UPDATE Employees SET ");
sb.Append("firstname='{0}',");
sb.Append("lastname='{1}',");
sb.Append("title='{2}',");
sb.Append("country='{3}' ");
sb.Append("WHERE employeeid={4}");
String cmd = sb.ToString();
sb = null;

TextBox fName = (TextBox) e.Item.Cells[1].Controls[0];
TextBox lName = (TextBox) e.Item.Cells[2].Controls[0];
TextBox position = (TextBox) e.Item.Cells[3].Controls[0];
TextBox country = (TextBox) e.Item.Cells[4].Controls[0];

cmd = String.Format(cmd,
fName.Text, lName.Text,
position.Text, country.Text,
grid.DataKeys[e.Item.ItemIndex]);

// Executes the command
OleDbConnection conn = new OleDbConnection(m_connString);
OleDbCommand c = new OleDbCommand(cmd, conn);
c.Connection.Open();
c.ExecuteNonQuery();
c.Connection.Close();

// Re-read from the database and updates the cache
DataFromSourceToMemory();
}
要檢索使用者在文字框中輸入的資訊,使用 e.Item.Cells[n].Controls[0] 運算式,其中n 是該列的索引(從 0 開始)。請記住,DataGrid 的就地編輯功能允許您通過將 “唯讀” 屬性設定為 true 來將列視為唯讀。

Delete 操作

Delete 操作的工作方式與 Insert 和 Update 操作大體相同。自動建立的列有一個命令名 Delete,在單擊該按鈕時會導致激發 ± 事件。內建的處理常式修複網格的介面,然後依次先後激發 DeleteData 和 UpdateView。

由於刪除操作的入侵性比插入或更新操作的強,因此您可能希望使用某個用戶端指令碼代碼,並要求使用者在繼續之前確認。我在 last month's column 的“對話方塊列”部分中討論了該方法。在本月的原始碼中,有一個如下圖所示的實際實現。



圖 3. 在刪除之前確認

最終的最佳化

我提到過 EditableGrid 控制項支援編輯模板。讓我來證明這一結論。在範例程式碼的第 2 步,我使用該網格中一組稍有不同的列。

<columns>
<asp:boundcolumn runat="server" headertext="ID"
datafield="employeeid" readonly="true" />
<asp:templatecolumn runat="server" headertext="Name">
<itemtemplate>
<%# DataBinder.Eval(Container.DataItem, "lastname") + ", " +
DataBinder.Eval(Container.DataItem, "firstname") %>
</itemtemplate>
<edititemtemplate>
<asp:textbox runat="server" id="lName"
text='<%#DataBinder.Eval(Container.DataItem, "lastname")%>' />
<asp:textbox runat="server" id="fName"
text='<%#DataBinder.Eval(Container.DataItem, "firstname")%>' />
</edititemtemplate>
</asp:templatecolumn>

<asp:boundcolumn runat="server" headertext="Position"
datafield="title" />
<asp:boundcolumn runat="server" headertext="Country"
datafield="country" />
</columns>
正如您可以看到的那樣,有一個模板列,它在單個欄位中顯示名和姓。此列的編輯模板(您必須指定能夠編輯該列的編輯模板)由兩個並排的文字框提供。無需在類中進行任何更改,即可獲得圖 4 中所示的樣本。



圖 4. 使用編輯模板

另一方面,在使用從文字框中檢索更新的文本的方式時,編輯模板需要進行少許調整。現在,可以按名稱檢索模板中的控制項。之所以可以並且建議這樣做,是因為您知道控制項的 ID。

TextBox fName = (TextBox) e.Item.FindControl("fName");
TextBox lName = (TextBox) e.Item.FindControl("lName");
TextBox position = (TextBox) e.Item.Cells[2].Controls[0];
TextBox country = (TextBox) e.Item.Cells[3].Controls[0];

在本月的原始碼中,您將發現該類的 C# 原始碼、兩個樣本 ASP.NET 頁以及我用過的 Access 資料庫。但是,您將找不到編譯過的程式集。我提供了一個(非常)簡單的批檔案,您可以使用它,針對與 beta 2 及其更高版本相容的任何版本的 .NET CLR,將該類編譯成為可執行代碼。

注 如果您在使下載正確運行時遇到問題,請檢查下列步驟:

• 1.將 CS 類編譯成為程式集。這可通過開啟一個 DOS 框並運行 ZIP 中的 c.bat 批次檔來完成,或者通過在 Visual Studio 中建立一個新的類庫項目並將類檔案添加到這個空白項目中來實現。

• 2.必須使程式集對於樣本 ASPX 頁可用。下載檔案中包括的批次檔將該 DLL 複製到 c:\inetpub\wwwroot\bin 檔案夾中。如果您恰好有一個不同的路徑,請對它進行修改。如果您建立一個虛擬目錄,請確保將該 DLL 複製到虛擬資料夾的 BIN 子檔案夾中,而不要複製到 Web 服務器根的 BIN 檔案夾中。

• 3.根據 ASP.NET 安全設定,在與樣本 Microsoft Access 資料庫互動時,可能會遇到難以處理的 Updateable Query 錯誤。在這種情況下,請更改樣本 .MDB 檔案的安全設定。在“Windows 資源管理員”中選擇該檔案,顯示內容,然後單擊安全選項卡。接著,添加 \ASPNET 使用者並確保它有權寫入和修改該檔案。

• 4.重新整理 ASPX 頁面。


對話方塊列:建立自訂模板

在上一個專欄中,您討論了 Summary 網格組件。是否有機會建立或載入合計列的自訂模板?這將允許在 ASPX 檔案中(而非代碼中)規定設計的規範。

使用合計列的自訂模板無疑將是可能的。問題只是在於如何??或者,更準確地說,哪種方法最簡單?我將在下面介紹幾種可能的方法。

• 使用 pagelet: 可以修改應用程式的代碼,使其動態載入 pagelet 控制項(又稱使用者控制項) — 即 ASCX 檔案。ASCX 檔案看上去像一個小型 Web Form,而且其中的大部分內容都是布局資訊。可以使用 Page.LoadControl 來按名稱載入 ASCX 檔案,然後將它添加到 DataGridItem 對象的某個儲存格的 Controls 集合中。

• 模板列:DataGrid 的所有列都是模板化列。使用 ASP.NET 標記和各處的一些代碼定義每一列的 。您能夠執行的操作就是將 塊的結構分成兩個截然不同且互斥的部分 — 一部分用於普通行,另一部分用於合計列。為了確保一次只顯示一行,可以處理控制項的 “可見” 屬性並將該屬性與界定合計列或普通行的條件綁定。

• 編寫新控制項:從 DataGrid 派生一個新類並添加一個新的模板屬性。這允許您使用自訂的子標記、按照與輸入列模板幾乎相同的方式輸入合計列布局。


返回頁首


相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。