GridView「新增」功能破解完整攻略

上一次我們提到,GridView不直接支援「新增」功能,小弟不才,經歷無數汗水(寫程式都吹冷氣,你騙誰!)與黑夜(自己不上床睡覺,還黑夜!),終於讓我寫出一個完整版的GridView新增功能,也就是說,依照此法,你光使用一個GridView控制項就能完整擁有「SELECT(顯示)、INSERT(新增資料)、DELETE(刪除)、UPDATE(更新)」等四大完整功能,不用再使用「GridView + FormView」、「GridView + DetailsView」…分開來實作「新增」功能,我們讓他們通通結合在一起,而且用起來「很順、有夠順、非常順、順到忘了他們的存在」。

此密技應該拿來出版賣錢,但恩師的讀者服務做的實在很好,所以我也決定「捐」出來送給大家。只有一個條件,請不要整篇轉貼,我的Blog沒有廣告,但也希望流量統計圖可以好看些^_^!

第一步:新增GridView + sqlDataSource

這個步驟沒有什麼技巧,一、先在畫面上拉GridView,二、新增資料連線,重點在sqlDataSource設定裡的「進階」必須產生Insert、Delete、Update等語法,這樣等一下GridView裡的新增才能直接使用此sqlDataSource的Insert語法。

第二步:增加「新增」功能

  1. 進入GridView的「編輯樣板」,選擇「EmptyDataTemplate」樣板;;
  2. 拉一個DetailsView進去EmptyDataTemplate,資料來源選擇與GridView同一來源(sqlDataSouce);原因上面說了,我們要使用同一資料來源裡的Inster語法;
  3. 設定DetailsView的DefaultMode為「Insert」;
  4. 勾選DetailsView的「啟用插入」

進入DetailsView的「編輯欄位」,找「選取的欄位」最下方的「CommandField(中文版是:新增、插入、取消)」,把ShowCancelButton屬性設為「False」;因為在EmptyDataTemplate樣板中DetailsView取消按鈕不會有作用,留下會讓使用者把到「把柄」說:「你的程式有Bug!」

第三步:在GridView新增觸發「新增」功能的按鈕

  1. 選擇GridView的「編輯欄位」;
  2. 加入一個「ButtonField」,移動一下位置;設定ButtonField屬性Text:設定為「新增」;
  3. (重點)設定ButtonField屬性CommandName="GridInsert"(名稱請自訂)

第四步:後置程式碼,讓GridView的「新增按扭」觸發「EmptyDataTemplate」樣板

我們必須寫第一段程式碼,讓我們的「新增」按鈕被按下時,能進到「EmptyDataTemplate」樣板,進而觸發裡面的「DetailsView」的Insert模式。我們必須透過GridView的RowCommand事件來觸發一些事情,進而進到「EmptyDataTemplate」樣板。

先想想,什麼時候我們會用到EmptyDataTemplate樣板?一般我們都在裡面寫「Sorry, No any data.」或「金排球,沒有任何美女圖!」就是你送給GridView的資料是「空空」的時候,所以我在RowCommand事件就是要讓GridView空空的,什麼都沒有。

Protected Sub GridView1_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles GridView1.RowCommand
        '中斷GridView與sqlDataSource的「綁定,Binding」,讓GridView進入EmptyDataTemplate樣板
        If e.CommandName = "GridInsert" Then
            GridView1.DataSourceID = Nothing
        End If
    End Sub

第五步:終極必殺--讓DetailsView有自動返回GridView的功能

接下來就是要教各位如果讓GridView提升為無敵控制項的密中密,請大家好好學,結果一定會讓大家大吃一驚,原來…我們永遠把事情想的太複雜

之前在「GridView」的「EmptyDataTemplate樣板」的「DetailsView」按「取消」鈕是沒有作用的,而你如果想回原始的GridView中,只能單純使用Browser的「上一頁」來解決,不過這不是我的菜,事情終有解決的一天,讓我們來解決這個大魔王把!

進入「EmptyDataTemplate樣板」:以下的解法有兩種,但不可思議的是它們還共用同一段程式碼(for Visual Studio 2010/.NET Framework 4.0)。

五之一:在DetailsView外使用Button按鈕

在EmptyDataTemplate樣板中隨便找個地方,從「標準」工具中拉一個「Button」控制項
設定Button屬性:ID為「bntBack」,Text為「Back GridView」
  1. (點重一)然後請在畫面上點Button控制項點兩下,進入程式碼編輯模式;第一:請注意程式碼最後,沒有Handles bntBack.Click;第二,那我們要寫什麼程式呢?…想想可樂果…我們前面是如何進行「EmptyDataTemplate樣板」,讓GridView的資料是「空空」的時候,相反的,我要離開EmptyDataTemplate樣板呢?讓GridView的資料是「不是空空」的時候。

Protected Sub bntBack_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        'sqlDSNW請修改為自己的名稱
        GridView1.DataSourceID = "sqlDSNW"
    End Sub

完成,總共寫了「四行」程式碼就完成一個超完整「新增、修改、刪除、更新」功能的「GridView」,重點是新增功能可正常運作,而且不用依賴Browser的「上一頁」來返回GridView。(大家拍拍手)

但這個按扭放在DetailsView之外,怎麼看都不順眼,對不對!那我們再來「手動自訂『取消」按鈕」吧。

五之二:在DetailsView內手動自訂取消鈕

原本DetailsView裡的「取消」鈕已經被我們設定為「False」,所以我們要新增「假按扭」來取代原有的「取消」鈕。
  1. (重點)在DetailsView中進入「編輯欄位」,選擇下方「CommandField(中文版是:新增、插入、取消)」,然後轉換為TemplateField欄位,回到DetailsView中;
  2. 選擇「編輯樣板」的「InsertItemTemplate」;新增作用在InsertItem樣板;
  3. 從「標準」工具中拉一個「Button」控制項(LinkButton或ImageButton也可以)到InsertItemTemplate樣板中;
  4. 設定Button屬性:Text為「Back GridView」;ID為「bntBack」;
  5. (重點)在Button控制項上點兩下,進入後置程式碼;
  6. 結束所有樣板編輯

Protected Sub bntBack_Click1(ByVal sender As Object, ByVal e As System.EventArgs)
        'sqlDSNW請修改為自己的名稱
        GridView1.DataSourceID = "sqlDSNW"
    End Sub

ps..這裡我是故意把兩個Button取同樣的名稱,我發現在VS2008與VS2010(或應該說.NET Framework 2.0與4.0的CLR)一些差異,在VS2008中,會建成Click與Click1兩個副程式,但在VS2010中它會很聰明共用同一個Click副程式,所以會少打一行程式碼。但實務上應該會不有人那麼無聊沒事放兩個Back的按鈕,而且還取相同名稱。當然也可能是表頭放一個、表尾放一個,但名子不要一樣,一行程式應該不會影響你很多效能與時間吧!

以上就完成了可以回到GridView的DetailsView了,重點很簡單:
  1. 不管是在DetailsView內外,都必須使用「Button控制項」(含LinkButton與ImageButton),因為我們需要Click副程式來做些事;
  2. DetailsView的Button控制項,點兩下,讓Visual Studio幫我們產生對應Click副程式;
  3. DetailsView的Button控制項,因為我們希望是放在「插入」旁邊,所以我們必須先讓「CommandField」轉換為TemplateField欄位,再進入「InsertItemTemplate」放入Button控制項,點兩下,讓Visual Studio幫我們產生對應Click副程式;
  4. 在Click副程式裡,讓GridView與sqlDataSource回復綁定(Binding),GridView就會取消EmptyDataTemplate樣板,回到原始顯示資料的模式。
ps..基本上只要資料控制項有支援「Insert」功能,都能拿來做GridView的新增功能控制項,再利用上敘方法加入返回GridView頁面功能即可。

32 則留言:

  1. 不好意思,請問一下第三步驟看不太懂,我的是2005的,是不是做不出來?我也沒看到"啟用插入"

    回覆刪除
  2. Dear oreo
    我沒有使用過Visual Studio 2005,So...
    找個時間,我在補上一篇有圖片。

    回覆刪除
  3. 謝謝您的教學很詳細:)
    只是打擾您了!如果在第四步觸動了DetailsView時,如何將現在日期(即設定預設值)給要新增日期的欄位呢?!
    假設:日期的欄位為TextBox,當一起動DetailsView時,該欄位便出現現在的日期,接著點選「新增」按鈕,可以將該筆資料(包含日期)寫進資料庫的資料表裡面。

    回覆刪除
  4. 在DetailsView的「程式碼」中,找到TextBox欄位,在欄位中寫程式,將日期值給TextBox,而且如果不希望人員修改,順便將TextBox設成唯讀。

    回覆刪除
  5. 請問我測試時,在DetailsView裡面輸入資料後卻需要儲存嗎?因為按下Back GridView後,沒看到剛輸入的資料,請問要如何儲存呢?

    回覆刪除
  6. DetailsView + sqldatasource,應該是能正常運作才是。

    回覆刪除
  7. http://kkbruce.blogspot.com/2010/07/gridview.html
    新增圖文篇,如果文字不清楚的請參考。

    回覆刪除
  8. 想請問一下,我是另外拉出一個DetailsView,然後裡面有一個日期的選項,是使用CalendarExtender小日曆的選取方式,按下儲存後,日期卻存不進去,請問有方式可以解決嗎?

    回覆刪除
  9. 日曆選取後應該能放入「Textbox」內,然後按儲存後就應該進資料庫中。

    如果是使用Datasource,請確認你的datasource裡SQL部份,是否有啟用「修改」。

    回覆刪除
  10. 真是好棒的密招
    照著大大的方法一步一步做, 真是又順又好用!
    做完想到一個點子, 但不知從何下手
    若在最後點 "插入"時, 會自動返回 GRIDVIEW 而不用手去點 Back GridView, 就更棒了, 要找到點完插入後會觸發的事件或什麼方法把 GridView1.DataSourceID = "sqlDSNW" 觸發

    回覆刪除
  11. Dear easyasp:
    因為我們是透過共用sqldatasource來做到這個效果,除非你是手動寫程式,才有辦法去控制怎麼細的動作。

    原理一樣,DetailsView新增動作後,去將 GridView1.DataSourceID = "sqlDSNW"連回去即可。

    程式大約是這樣:
    Try
    Using sqlDS As New SqlDataSource()
    sqlDS.ConnectionString = WebConfigurationManager.ConnectionStrings("sqlDSNW").ConnectionString
    sqlDS.InsertCommandType = SqlDataSourceCommandType.Text
    sqlDS.InsertCommand = "insert into [Table_Name] (F1, F2, F3, F4) Values (@V1, @V2, @V3, @V4)"
    sqlDS.InsertParameters.Add("V1", T1.Text)
    sqlDS.InsertParameters.Add("V2", T2.Text)
    sqlDS.InsertParameters.Add("V3", T3.Text)
    sqlDS.InsertParameters.Add("V4", T4.Text)

    ' DetailsView的新增
    Dim rows As Integer = sqlDS.Insert()
    lblMsg.Text = "成功新增 " & rows.ToString() & " 筆資料."
    ' 新增後回GridView
    GridView1.DataSourceID = "sqlDSNW"
    End Using
    Catch ex As Exception
    lblMsg.Text = "Insert Data Error:" & ex.Message
    End Try

    回覆刪除
  12. 你講的超級詳細的~
    初學者也會用:)

    回覆刪除
  13. 正需要這東西!!!
    感謝分享,馬上來實做

    回覆刪除
  14. 可否請問一下, 我設定 Detailsview 的啟用插入之後 它跑出一個錯誤訊息:
    System.Web.UI.WebControls.DataControlFieldCollection 必須有屬於型別 System.Web.UI.WebControls.DataControlField的項目
    'strong'是屬於型別 System.Web.UI.HtmlControls.HtmlGenericControl'

    這是怎麼回事呢?

    回覆刪除
  15. Sorry 虛驚一場, 只是不小心把Gridview 跟 Detailsview 給加到 "< S t r o n g >< S p a n > .................< /S p a n >< / S t r o n g >" 中間去了@@

    回覆刪除
  16. 對我這個剛開始在摸的初學者來說,真的太感謝了!~

    回覆刪除
  17. 請問有C#版本的嗎??

    回覆刪除
    回覆
    1. 以上如果熟 GridView + DataSqlSource,重點步驟都一模一樣,
      程式碼部分,唯一不一樣 … @_@

      VB:
      If e.CommandName = "GridInsert" Then
      GridView1.DataSourceID = Nothing
      End If

      C#:
      If (e.CommandName = "GridInsert") {
      GridView1.DataSourceID = null;
      }

      刪除
  18. 鬧了一個大笑話
    弄了老半天
    才知道大大給的是VB
    不是C#....

    回覆刪除
  19. 如果有源碼提供下載 就更完美了

    回覆刪除
    回覆
    1. 都有圖文解說版…自己實作一下吧!@_@

      刪除
  20. 請問一下 用c# 編輯 後製碼 使得 gridview 可以做新增 修改 刪除 的動作而不是前置碼 該如何去做呢

    回覆刪除
  21. 您好: 因為我是.NET初學者,您的文章淺顯易懂讓我受益良多,感謝。

    回覆刪除
  22. 您好~請問我在做第四步時,會出現"無法指定屬性或索引子 其為唯讀"這個錯誤,我是使用c#,VS2010~該怎麼解決呢?謝謝!

    回覆刪除
  23. 剛剛Try了一下發現,新增完後如果要直接跳回Gridview頁面,把 GridView1.DataSourceID = "sqlDSNW" 事件放在 sqlDataSource_Inserted 事件裡就可以了 ,大概長的像下面這樣子~

    protected void sqlDataSource_Inserted (object sender, SqlDataSourceStatusEventArgs e)
    {
    GridView1.DataSourceID = "sqlDSNW";
    }

    回覆刪除
  24. 您好~請問我在做第四步時,會出現"無法指派屬性或索引子 其為唯讀"這個錯誤,我是使用c#,請問該怎麼解決呢?謝謝!

    回覆刪除

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。