DataGrid (經典控件,現代項目建議用 GridView)CREATE TABLE Messages (
Id INT PRIMARY KEY IDENTITY(1,1),
Title NVARCHAR(200) NOT NULL,
Content NVARCHAR(MAX) NOT NULL,
Author NVARCHAR(50) NOT NULL,
CreateTime DATETIME DEFAULT GETDATE()
);
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="MessageBoard.aspx.cs" Inherits="MessageBoard.MessageBoard" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>簡易留言板</title>
<style>
.grid { width: 100%; border-collapse: collapse; margin-top: 20px; }
.grid th, .grid td { border: 1px solid #ddd; padding: 8px; text-align: left; }
.grid th { background-color: #f2f2f2; }
.form-group { margin-bottom: 15px; }
label { display: inline-block; width: 80px; vertical-align: top; }
textarea { width: 400px; height: 100px; }
.btn { padding: 6px 12px; margin-right: 10px; cursor: pointer; }
</style>
</head>
<body>
<form id="form1" runat="server">
<h2>留言板</h2>
<!-- 發布留言表單 -->
<div class="form-group">
<label>標題:</label>
<asp:TextBox ID="txtTitle" runat="server" Width="400px" />
</div>
<div class="form-group">
<label>作者:</label>
<asp:TextBox ID="txtAuthor" runat="server" Width="200px" />
</div>
<div class="form-group">
<label>內容:</label><br />
<asp:TextBox ID="txtContent" runat="server" TextMode="MultiLine" Rows="5" Cols="50" />
</div>
<asp:Button ID="btnPost" runat="server" Text="發布留言" CssClass="btn" OnClick="btnPost_Click" />
<!-- 留言列表 -->
<asp:DataGrid ID="dgMessages" runat="server" CssClass="grid"
AutoGenerateColumns="False"
OnDeleteCommand="dgMessages_DeleteCommand"
DataKeyField="Id"
AllowPaging="True" PageSize="10"
OnPageIndexChanged="dgMessages_PageIndexChanged">
<Columns>
<asp:BoundColumn DataField="Id" HeaderText="ID" ReadOnly="True" />
<asp:BoundColumn DataField="Title" HeaderText="標題" />
<asp:BoundColumn DataField="Author" HeaderText="作者" />
<asp:BoundColumn DataField="CreateTime" HeaderText="發布時間" DataFormatString="{0:yyyy-MM-dd HH:mm}" />
<asp:TemplateColumn HeaderText="內容">
<ItemTemplate>
<asp:Label ID="lblContent" runat="server" Text='<%# Eval("Content") %>' />
</ItemTemplate>
</asp:TemplateColumn>
<asp:ButtonColumn CommandName="Delete" Text="刪除" HeaderText="操作"
ButtonType="LinkButton"
OnClientClick="return confirm('確定要刪除這條留言嗎?');" />
</Columns>
</asp:DataGrid>
</form>
</body>
</html>
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web.UI.WebControls;
namespace MessageBoard
{
public partial class MessageBoard : System.Web.UI.Page
{
private string connStr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindData();
}
}
// 綁定數據
private void BindData()
{
using (SqlConnection conn = new SqlConnection(connStr))
{
string sql = "SELECT Id, Title, Author, Content, CreateTime FROM Messages ORDER BY CreateTime DESC";
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
DataTable dt = new DataTable();
da.Fill(dt);
dgMessages.DataSource = dt;
dgMessages.DataBind();
}
}
// 發布留言
protected void btnPost_Click(object sender, EventArgs e)
{
string title = txtTitle.Text.Trim();
string author = txtAuthor.Text.Trim();
string content = txtContent.Text.Trim();
if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(content))
{
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('標題和內容不能為空!');", true);
return;
}
using (SqlConnection conn = new SqlConnection(connStr))
{
string sql = "INSERT INTO Messages (Title, Author, Content) VALUES (@Title, @Author, @Content)";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@Title", title);
cmd.Parameters.AddWithValue("@Author", string.IsNullOrEmpty(author) ? "匿名" : author);
cmd.Parameters.AddWithValue("@Content", content);
conn.Open();
cmd.ExecuteNonQuery();
}
// 清空表單並刷新
txtTitle.Text = "";
txtAuthor.Text = "";
txtContent.Text = "";
BindData();
}
// 刪除留言
protected void dgMessages_DeleteCommand(object source, DataGridCommandEventArgs e)
{
int id = (int)dgMessages.DataKeys[e.Item.ItemIndex];
using (SqlConnection conn = new SqlConnection(connStr))
{
string sql = "DELETE FROM Messages WHERE Id = @Id";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@Id", id);
conn.Open();
cmd.ExecuteNonQuery();
}
BindData();
}
// 分頁
protected void dgMessages_PageIndexChanged(object source, DataGridPageChangedEventArgs e)
{
dgMessages.CurrentPageIndex = e.NewPageIndex;
BindData();
}
}
}
<connectionStrings>
<add name="DefaultConnection"
connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\MessageBoard.mdf;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
| 功能 | 核心實現 | 注意事項 |
|---|---|---|
| 數據綁定 | DataGrid.DataSource = DataTable; DataGrid.DataBind(); | 只在 !IsPostBack 或數據變更後調用 |
| 參數化查詢 | cmd.Parameters.AddWithValue("@Param", value) | **防止 SQL 注入**,必須養成習慣 |
| 刪除操作 | ButtonColumn CommandName="Delete" + OnDeleteCommand | 用 DataKeys 獲取主鍵,配合 JS 確認框 |
| 分頁 | AllowPaging="True" PageSize="10" + OnPageIndexChanged | 分頁事件中重置 CurrentPageIndex 並重新綁定 |
| XSS 防護 | 輸出時編碼:Server.HtmlEncode() 或 Razor 自動編碼 | 留言內容含 HTML 標籤時必須編碼顯示 |
新項目建議使用 ASP.NET Core + Razor Pages / MVC + Entity Framework Core,配合 GridView 或前端框架。Web Forms 屬於維護模式,學習目的可參考本例,生產環境請選擇現代技術棧。