2017年7月22日 星期六

ASP.NET 利用JavaScript達到多檔上傳

這是大學時期的畢業專題,曾經寫過的一個「多檔上傳」的功能,參考國外的文章,至於那篇文章,我也沒特別留下來,今天特別找出來記錄,以防哪一天需要用的時候就可以使用,這也是大學時期對一個剛學程式的學生來講,特別有成就感的一個功能;在這裡還是要提一下檔案上傳可能會影響的資安問題(ASP.NET FileUpload上傳檔案,讀取Byte檢查副檔名,以圖片為例)。

執行結果

Step 1.先設定Web.config
<configuration>
    <system.web>
      <compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
      <!-- 可修改maxRequestLength的值來改變上傳限制,單位為K,4096=4MB,15360=15MB -->
      <httpRuntime maxRequestLength="15360"/>
    </system.web>
</configuration>

Step 2.test_multi-file_fileupload.aspx
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="test_multi-file_fileupload.aspx.vb" Inherits="test_multi_file_fileupload" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript">
        function addFileUploadBox() {
            if (!document.getElementById || !document.createElement) {
                return false;
            };
            //取得id叫作upload-area元素
            var uploadArea = document.getElementById('upload-area');
            if (!uploadArea) {
                return false;
            };
            //建立br元素(在Html中叫作換行)
            var newLine = document.createElement('br');
            //在upload-area中加入換行
            uploadArea.appendChild(newLine);
            //建立input元素
            var newUploadBox = document.createElement('input');
            newUploadBox.type = 'file'; //input的類型為file檔案類型
            newUploadBox.size = '40';
            if (!addFileUploadBox.lastAssignedId) {
                addFileUploadBox.lastAssignedId = 100;
            };
            //設定input的id、name
            newUploadBox.setAttribute('id', 'FileF' + addFileUploadBox.lastAssignedId);
            newUploadBox.setAttribute('name', 'FileF:' + addFileUploadBox.lastAssignedId);
            uploadArea.appendChild(newUploadBox);
            addFileUploadBox.lastAssignedId++;
        };
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>測試多檔上傳</h1>
        附加檔案:<br/>
        <p id="upload-area">
            <input id="FileField" type="File" runat="server" size="40" />
        </p>
        <input id="ButtonAdd" type="button" value="繼續附加" onclick="addFileUploadBox();" />&nbsp;&nbsp;
        <asp:Button ID="Button1" runat="server" Text="開始上傳" /><span style=" color:red;">檔案附加不可超過10MB</span><br/>
        <asp:Label ID="Send_msg" runat="server"></asp:Label>
    </div>
    </form>
</body>
</html>

Step 3.test_multi-file_fileupload.aspx.vb
Imports System.IO
Partial Class test_multi_file_fileupload
    Inherits System.Web.UI.Page

    Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        '======================
        Dim uploads As HttpFileCollection = Nothing
        uploads = HttpContext.Current.Request.Files
        Dim FileToUpload As HttpPostedFile = Nothing
        '======================
        '計算全部附加檔案的大小
        Dim x_KB As Integer = 0, x_Byte As Integer = 0
        Dim x_MB As Double
        For i As Integer = 0 To (uploads.Count - 1)
            FileToUpload = uploads(i)
            x_Byte = x_Byte + FileToUpload.ContentLength
        Next
        x_KB = x_Byte / 1024 'Byte / 1024=KB
        x_MB = x_KB / 1024 'KB / 1024=MB
        '信件傳送不能超過或等於10MB
        If Int(x_MB) >= 10 Then '取整數
            '否則>=10MB
            '所有的附加檔案不能超過或等於10MB
            Send_msg.Text = "注意:所有的附加檔案加起來不能超過或等於10MB"
            Send_msg.ForeColor = Drawing.Color.Red
            Exit Sub
        End If
        '======================
        Dim us_f As UShort = 0 '檔案是否重複,重複為1,不重複0
        Dim str_FolderName As String = "File"
        Dim GEM_MSG As New StringBuilder
        Dim FilePath() As String = Nothing '存放檔案路徑
        Dim AYN As Integer = -1
        For i As Integer = 0 To (uploads.Count - 1)
            FileToUpload = uploads(i)
            ReDim Preserve FilePath(i)
            If FileToUpload.FileName <> "" Then
                AYN = AYN + 1
                '建立檔案路徑
                '第三個參數:指定看由哪一個網頁呼叫此程序,就必須在那個目錄下建立資料夾
                FilePath(i) = ServerFilePath(FileToUpload, System.IO.Path.GetFileName(FileToUpload.FileName), str_FolderName) '串聯路徑
                '===============================
                Dim FileName As String = Nothing

                If (FileToUpload.ContentLength <> 0) Then
                    'System.IO.Path.GetFileNameWithoutExtension(FileToUpload.FileName) '取檔案名稱,不包含副檔名
                    'System.IO.Path.GetExtension(FileToUpload.FileName) '取副檔名
                    '判斷檔案名稱是否有重複
                    If File.Exists(FilePath(i)) = True Then
                        Dim Uploadfile As String
                        Uploadfile = HttpContext.Current.Server.MapPath(str_FolderName) '會指定看由哪一個網頁呼叫此程序,就必須在那個目錄下建立資料夾
                        Dim Repeat_Number As Integer = 0
                        While (File.Exists(FilePath(i)))
                            Repeat_Number = Repeat_Number + 1
                            '如果存在就更改檔名
                            FileName = System.IO.Path.GetFileNameWithoutExtension(FileToUpload.FileName) & "(" & Repeat_Number & ")" &
                            System.IO.Path.GetExtension(FileToUpload.FileName)
                            FilePath(i) = Uploadfile + "\" + FileName
                        End While
                        GEM_MSG.Append("<span style=" & Chr(34) & "color:red;" & Chr(34) & ">附加檔案名稱以重複,檔案名稱修改為" & FileName)
                    Else
                        GEM_MSG.Append("<span style=" & Chr(34) & "color:blue;" & Chr(34) & ">" & System.IO.Path.GetFileName(FileToUpload.FileName))
                    End If
                End If
                Try
                    FileToUpload.SaveAs(FilePath(i))
                    GEM_MSG.Append(",附加成功</span><br />")
                Catch ex As Exception
                    GEM_MSG.Append(",附加失敗</span><br />")
                    'GEM_MSG.Append(",附加失敗" & ex.ToString & "</span><br />")
                End Try
                '===============================
            Else
                FilePath(i) = ""
            End If
            If i = uploads.Count - 1 And AYN <> -1 Then
                GEM_MSG.Append("<hr size=" & Chr(34) & "1" & Chr(34) & " />")
            End If
        Next
        Send_msg.Text = GEM_MSG.ToString
        Send_msg.ForeColor = Drawing.Color.Black

    End Sub

    '建立檔案路徑,
    Function ServerFilePath(ByVal FileToUpload As HttpPostedFile, ByVal FileName As String, ByVal Folder_name As String) As String

        Dim Uploadfile As String
        Uploadfile = HttpContext.Current.Server.MapPath(Folder_name) '會指定看由哪一個網頁呼叫此程序,就必須在那個目錄下建立資料夾
        If Directory.Exists(Uploadfile) = False Then '檢查目錄存不存在
            '不存在就建立資料夾
            Directory.CreateDirectory(Uploadfile)
        End If
        If (FileToUpload.ContentLength <> 0) Then
            Uploadfile = Uploadfile + "\" + FileName '建立檔案路徑
        Else
            Uploadfile = ""
        End If
        Return Uploadfile
    End Function
End Class



2017年7月15日 星期六

ASP.NET Word套表產生的docx檔,多檔合併


參考資料:
[Updated] How To: Merge Multiple Microsoft Word Documents | Keith Rull
主要是參考這篇資料,有範例檔

繼上一篇「ASP.NET 使用TemplateEngine.Docx套件,Word套表產生docx檔」後,假如使用者在使用的過程中,產生出很多docx檔時,總不能讓使用者一個一個套表下載吧!  因此須製作一個功能,可以讓使用者可以一次將多個docx檔合併到同一個docx檔。

Step 1.首先要將 Microsoft Word 12.0 Object Library 加入參考到自己的專案中,這個步驟應該要看自己的電腦安裝哪一種Office,有的可能找不到12.0 Object Library,那就用其他版本試試看或者是使用Microsoft.Office.Interop.Word.dll檔加入參考。

Step 2.請在自己的專案中建立3個資料夾,分別是news_merge_word、temp_word、Template_Word,說明如下:
news_merge_word資料夾主要是存放已經合併完成的docx檔。
temp_word資料夾存放程式套好表的docx檔。
Template_Word資料夾只存放一個空到Word檔,你可以想像這個Word檔是將多的docx檔存放到同一個docx檔,這個空的word檔檔名為 normal.docx,你可以先設定好normal.docx上下左右的邊界,當多個docx檔合併到normal.docx時,會依照normal.docx的邊界下去合併。

Step 3.建立一個aspx網頁,畫面上只需要一個Button1按鈕,並在這個按鈕上建立Click事件。
以下為程式碼,程式碼的部分我是參考上方的參考資料
Imports System
Imports Word = Microsoft.Office.Interop.Word

Partial Class test_word_multi_file_merge
    Inherits System.Web.UI.Page

    Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim str_path As String = String.Empty
        '假設陣列中,是已經透過程式word套表,產生出的docx檔
        Dim str_arrfile() As String = {Server.MapPath("~/temp_word/word1.docx"), Server.MapPath("~/temp_word/word2.docx"), Server.MapPath("~/temp_word/word3.docx")}

        '第二個參數是將合併後的word檔,給予新的檔案名稱、第三個參數是否要有分頁符號
        Merge(str_arrfile, Server.MapPath("~/news_merge_word/new_merge_word_" & Date.Now.ToString("yyyyMMddHHmmss") & ".docx"), True, Page)
    End Sub

    Sub Merge(ByVal filesToMerge As String(), ByVal outputFilename As String, ByVal insertPageBreaks As Boolean, ByVal this_page As Page)
        'normal.docx檔(可以針對normal.docx先設定好邊界)是空白的word檔,可以把它想像成,把多個word檔合併到normal.docx;
        Merge(filesToMerge, outputFilename, insertPageBreaks, Server.MapPath("~/Template_Word/normal.docx"))
    End Sub


    Sub Merge(ByVal filesToMerge As String(), ByVal outputFilename As String, ByVal insertPageBreaks As Boolean, ByVal documentTemplate As String)
        Dim defaultTemplate As Object = documentTemplate
        Dim pageBreak As Object = Word.WdBreakType.wdPageBreak
        Dim outputFile As Object = outputFilename

        ' Create a new Word application
        Dim wordApplication As Word._Application = New Word.Application()

        Try
            ' Create a new file based on our template
            Dim wordDocument As Word._Document = wordApplication.Documents.Add(defaultTemplate)

            ' Make a Word selection object.
            Dim selection As Word.Selection = wordApplication.Selection

            'Count the number of documents to insert;
            Dim documentCount As Integer = filesToMerge.Length

            'A counter that signals that we shoudn't insert a page break at the end of document.
            Dim breakStop As Integer = 0

            ' Loop thru each of the Word documents
            For Each file As String In filesToMerge
                breakStop += 1
                ' Insert the files to our template
                selection.InsertFile(file)

                'Do we want page breaks added after each documents?
                If insertPageBreaks AndAlso breakStop <> documentCount Then
                    selection.InsertBreak(pageBreak) '插入分頁
                End If
            Next

            ' Save the document to it's output file.
            wordDocument.SaveAs(outputFile)

            ' Clean up!
            wordDocument = Nothing
        Catch ex As Exception
            'I didn't include a default error handler so i'm just throwing the error
            Throw ex
        Finally
            ' Finally, Close our Word application
            wordApplication.Quit()
        End Try
    End Sub

End Class

2017年7月14日 星期五

ASP.NET UpdatePanel + GridView 插入資料列、刪除資料列

參考資料1:Adding Dynamic Rows in ASP.Net GridView Control with TextBoxes (這篇是重點)
參考資料2:Sys.WebForms.PageRequestManager endRequest 事件

繼上一篇「ASP.NET GridView 按下按鈕,加入新的資料列」,在GridView下方有一個加入按鈕,按下「加入」按鈕後插入新的資料列,這次我想再加上一些功能,在每一列有刪除按鈕,按下「刪除」按鈕便能刪除GridView的資料列,為了不讓PostBack,刷新頁面,我打算加上UpdatePanel ;而在這個功能中,我有一個欄位是期間欄位,可以讓使用者去設定一段區間日期,為了作到這個效果我使用了bootstrap-datetimepicker套件,但是在測試的過程中,因為會插入新的資料列,而造成JQuery失效。

為什麼想製作這個功能,原因是有時候使用者可能只是先將資料key在一個資料表中,但是還沒真正的寫到資料庫裡,等於是暫時儲存起來,最後確認時,再送出所有的資料。

執行結果:

步驟1.先製作一個MasterPage1.master
<%@ Master Language="VB" CodeFile="MasterPage1.master.vb" Inherits="MasterPage1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head runat="server">
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>test_gv_addrow_delectrow</title>
    <link rel="stylesheet" href="css/bootstrap.css" />
    <link rel="stylesheet" href="css/CustStyle1.css"/>
    <script src="js/jquery-1.11.3.js"></script>
    <script src="js/bootstrap.js"></script>
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    <asp:ContentPlaceHolder id="head" runat="server">
    </asp:ContentPlaceHolder>
    <style type="text/css">
        body {
        background-color:#ffffff; /*背景顏色*/
        }
        .navbar {
        margin-bottom:0px;
        }
        .rowcol2 {
            padding-right:0px;
            padding-left:0px;
        }
        .custfooter {
            margin-top: 30px;
        }
    </style>
  </head>
  <body>
    <form id="form1" runat="server">
        <!--第一層-開始-->
        <nav class="navbar navbar-default">
            <div class="container-fluid">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand"><strong>test_gv_addrow_delectrow</strong></a>
                </div>
            </div>
        </nav>
        <!--第一層-結束-->
        <asp:ContentPlaceHolder id="CPH1" runat="server">
     
        </asp:ContentPlaceHolder>
        <div class="container-fluid">
        </div>
    </form>
  </body>
</html>

步驟2.建立test_gv_addrow_delectrow2.aspx
<%@ Page Title="" Language="VB" MasterPageFile="~/MasterPage1.master" AutoEventWireup="false" CodeFile="test_gv_addrow_delectrow2.aspx.vb" Inherits="test_gv_addrow_delectrow2" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
    <link rel="stylesheet" href="css/bootstrap-datetimepicker.min.css" />
    <script src="js/moment.min.js"></script>
    <script src="js/moment.zh-tw.js"></script>
    <script src="js/bootstrap-datetimepicker.min.js"></script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="CPH1" Runat="Server">
    <div class="container">
        <div class="row">
            <div class="col-xs-12">
                <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
                測試加入UpdatePanel
                <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
                    <ContentTemplate>
                        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" ShowFooter="true">
                            <Columns>
                                <asp:TemplateField HeaderText="">
                                    <ItemTemplate>
                                        <asp:Button ID="BDelete" runat="server" CommandName="dr" CssClass="btn btn-danger" Text="刪除" />
                                    </ItemTemplate>
                                </asp:TemplateField>
                                <asp:TemplateField HeaderText="順序號">
                                    <ItemTemplate>
                                        <asp:Label ID="L_order" runat="server"></asp:Label>
                                    </ItemTemplate>
                                </asp:TemplateField>
                                <asp:TemplateField HeaderText="期間">
                                    <ItemTemplate>
                                        <div class="form-group row has-success">
                                            <div class="col-xs-6">
                                                <asp:TextBox ID="TextBox1" runat="server" CssClass="form-control cust-date"></asp:TextBox>
                                            </div>
                                            <div class="col-xs-6">
                                                <asp:TextBox ID="TextBox2" runat="server" CssClass="form-control cust-date"></asp:TextBox>
                                            </div>
                                        </div>
                                    </ItemTemplate>
                                    <FooterStyle HorizontalAlign="left" />
                                    <FooterTemplate>
                                        <asp:Button ID="ButtonAdd" runat="server" CommandName="addrow" CssClass="btn btn-primary" Text="加入" />
                                    </FooterTemplate>
                                </asp:TemplateField>
                                <asp:TemplateField HeaderText="欄位2">
                                    <ItemTemplate>
                                        <div class="form-group row has-success">
                                            <div class="col-xs-12">
                                                <asp:TextBox ID="TextBox3" runat="server" CssClass="form-control"></asp:TextBox>
                                            </div>
                                        </div>
                                    </ItemTemplate>
                                </asp:TemplateField>
                                <asp:TemplateField HeaderText="欄位3">
                                    <ItemTemplate>
                                        <div class="form-group row has-success">
                                            <div class="col-xs-12">
                                                <asp:TextBox ID="TextBox4" runat="server" CssClass="form-control"></asp:TextBox>
                                            </div>
                                        </div>
                                    </ItemTemplate>
                                </asp:TemplateField>
                            </Columns>
                            <EmptyDataTemplate>
                                <asp:Label ID="GV_Empty" runat="server" Text="目前無資料"></asp:Label>
                            </EmptyDataTemplate>
                        </asp:GridView>
                        <script type="text/javascript">
                            $(document).ready(function () {
                                bind_TextBox();
                            });

                            //Sys.WebForms.PageRequestManager.getInstance是asp.net提供的
                            var prm = Sys.WebForms.PageRequestManager.getInstance();
                            if (prm != null) {
                                //add_endRequest 在完成非同步回傳之後,且已將控制項傳回瀏覽器時引發。
                                prm.add_endRequest(EndRequestHandler);
                            };
                            function EndRequestHandler(sender, args) {
                                if (typeof (args.get_error()) != 'undefined') {
                                    bind_TextBox(); //重新套用datetimepicker,如果不這麼作,所有的GridView中的TextBox將會失效
                                };
                            };
                         
                            //=========================================
                            //bind_TextBox2方法是最初的寫法,但是會有問題,按下加入按鈕後,JQuery就失效了,除了第一列的TextBox外,
                            //所以我改了另外一種寫法,就是在TextBox的CssClass屬性加入css的類別,再使用選擇器$('.cust-date')去抓取所有的TextBox並套用datetimepicker,可以看bind_TextBox方法
                            var str_arrid = [<%=str_js_arrid.ToString%>];
                            function bind_TextBox2(str_call) {
                                for (var x = 0; x <= str_arrid.length - 1; x++) {
                                    $('#' + str_arrid[x]).prop('readonly', true);
                                    $('#' + str_arrid[x]).datetimepicker({ locale: 'zh-tw', format: 'YYYY/MM/DD', ignoreReadonly: true });
                                };
                            };
                            <% str_js_arrid.Clear() : str_js_arrid = Nothing%>
                            //=========================================
                            function bind_TextBox() {
                                $('.cust-date').prop('readonly', true);
                                $('.cust-date').datetimepicker({ locale: 'zh-tw', format: 'YYYY/MM/DD', ignoreReadonly: true });
                            };
                        </script>
                    </ContentTemplate>
                    <Triggers>
                        <asp:AsyncPostBackTrigger ControlID="GridView1" EventName="RowCommand" />
                    </Triggers>
                </asp:UpdatePanel>
            </div>
        </div>
    </div>
</asp:Content>

說明:
1.黃色標起來的部分,是參考「參考資料2」,作用是為了讓datetimepicker重新被套用。
2.綠色標起來的部分,是我修改過後的寫法,可以正常運作。
3.紅色標起來的部分,是有問題的,當我按下加入按鈕後,只有第一列的日期還有作用,第一列之後加入的,就沒有任何作用,請注意看紅色註解。


步驟3.test_gv_addrow_delectrow2.aspx.vb
Imports System.Data
Partial Class test_gv_addrow_delectrow2
    Inherits System.Web.UI.Page
    Public str_js_arrid As StringBuilder = Nothing

    Private Sub test_gv_addrow_delectrow2_Load(sender As Object, e As EventArgs) Handles Me.Load
        If Not Page.IsPostBack Then
            '自行建立datatabel給GridView
            Dim cust_dt As DataTable = SetInitialRow()
            GridView1.DataSource = cust_dt
            GridView1.DataBind()
            GridView1.CssClass = "table table-bordered"
        End If
    End Sub

    Function SetInitialRow() As DataTable
        Dim dt As DataTable = Nothing
        dt = New DataTable()
        Dim dr As DataRow = Nothing
        dt.Columns.Add(New DataColumn("Columns1", System.Type.GetType("System.Int32")))
        dt.Columns.Add(New DataColumn("date_start", System.Type.GetType("System.String")))
        dt.Columns.Add(New DataColumn("date_end", System.Type.GetType("System.String")))
        dt.Columns.Add(New DataColumn("Columns2", System.Type.GetType("System.String")))
        dt.Columns.Add(New DataColumn("Columns3", System.Type.GetType("System.String")))

        dr = dt.NewRow()
        dr("Columns1") = 0
        dr("date_start") = String.Empty
        dr("date_end") = String.Empty
        dr("Columns2") = String.Empty
        dr("Columns3") = String.Empty
        dt.Rows.Add(dr)
        'Store the DataTable in ViewState
        ViewState("CurrentTable") = dt

        Return dt

    End Function

    Sub AddNewRowToGrid()
        Dim rowIndex As Integer = 0
        If Not ViewState("CurrentTable") Is Nothing Then
            Dim dtCurrentTable As DataTable = Nothing
            dtCurrentTable = CType(ViewState("CurrentTable"), DataTable)
            Dim drCurrentRow As DataRow = Nothing

            If dtCurrentTable.Rows.Count > 0 Then
                '將目前的資料寫回DataTable
                For i As Integer = 1 To dtCurrentTable.Rows.Count
                    Dim TextBox1 As TextBox = CType(GridView1.Rows(rowIndex).Cells(1).FindControl("TextBox1"), TextBox)
                    Dim TextBox2 As TextBox = CType(GridView1.Rows(rowIndex).Cells(1).FindControl("TextBox2"), TextBox)
                    Dim TextBox3 As TextBox = CType(GridView1.Rows(rowIndex).Cells(2).FindControl("TextBox3"), TextBox)
                    Dim TextBox4 As TextBox = CType(GridView1.Rows(rowIndex).Cells(3).FindControl("TextBox4"), TextBox)

                    drCurrentRow = dtCurrentTable.NewRow()
                    dtCurrentTable.Rows(i - 1)("Columns1") = 0
                    dtCurrentTable.Rows(i - 1)("date_start") = TextBox1.Text
                    dtCurrentTable.Rows(i - 1)("date_end") = TextBox2.Text
                    dtCurrentTable.Rows(i - 1)("Columns2") = TextBox3.Text
                    dtCurrentTable.Rows(i - 1)("Columns3") = TextBox4.Text
                    rowIndex = rowIndex + 1
                Next
                dtCurrentTable.Rows.Add(drCurrentRow)
                ViewState("CurrentTable") = dtCurrentTable

                GridView1.DataSource = dtCurrentTable
                GridView1.DataBind()
                GridView1.CssClass = "table table-bordered"


            End If
        Else
            Response.Write("ViewState is null")
        End If

        'Set Previous Data on Postbacks
        SetPreviousData()
    End Sub

    Sub SetPreviousData()
        Dim rowIndex As Integer = 0
        If Not ViewState("CurrentTable") Is Nothing Then
            Dim dt As DataTable = Nothing
            dt = CType(ViewState("CurrentTable"), DataTable)
            If dt.Rows.Count > 0 Then
                For i As Integer = 0 To dt.Rows.Count - 1

                    Dim TextBox1 As TextBox = CType(GridView1.Rows(rowIndex).Cells(1).FindControl("TextBox1"), TextBox)
                    Dim TextBox2 As TextBox = CType(GridView1.Rows(rowIndex).Cells(1).FindControl("TextBox2"), TextBox)
                    Dim TextBox3 As TextBox = CType(GridView1.Rows(rowIndex).Cells(2).FindControl("TextBox3"), TextBox)
                    Dim TextBox4 As TextBox = CType(GridView1.Rows(rowIndex).Cells(3).FindControl("TextBox4"), TextBox)

                    TextBox1.Text = dt.Rows(i)("date_start").ToString()
                    TextBox2.Text = dt.Rows(i)("date_end").ToString()
                    TextBox3.Text = dt.Rows(i)("Columns2").ToString()
                    TextBox4.Text = dt.Rows(i)("Columns3").ToString()

                    rowIndex = rowIndex + 1
                Next
            End If
        End If
    End Sub

    Private Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
        If e.Row.RowType = DataControlRowType.Header Then
            e.Row.CssClass = "bg-primary"
            e.Row.Cells(0).CssClass = "col-xs-1 col-md-1"
            e.Row.Cells(1).CssClass = "col-xs-1 col-md-1"
            e.Row.Cells(2).CssClass = "col-xs-2 col-md-2"
            e.Row.Cells(3).CssClass = "col-xs-1 col-md-1"
            e.Row.Cells(4).CssClass = "col-xs-1 col-md-1"
            str_js_arrid = New StringBuilder()
            str_js_arrid.Append("")
        End If
        If e.Row.RowType = DataControlRowType.DataRow Then
            Dim L_order As Label = CType(e.Row.FindControl("L_order"), Label)
            Dim TextBox1 As TextBox = CType(e.Row.FindControl("TextBox1"), TextBox)
            Dim TextBox2 As TextBox = CType(e.Row.FindControl("TextBox2"), TextBox)
            If str_js_arrid.ToString = "" Then
                str_js_arrid.Append("'" & TextBox1.ClientID & "','" & TextBox2.ClientID & "'")
            Else
                str_js_arrid.Append(",'" & TextBox1.ClientID & "','" & TextBox2.ClientID & "'")
            End If
            TextBox1.Attributes.Add("placeholder", "請選擇開始期間日期")
            TextBox2.Attributes.Add("placeholder", "請選擇結束期間日期")
            L_order.Text = e.Row.RowIndex + 1
        End If
    End Sub

    Private Sub GridView1_RowCommand(sender As Object, e As GridViewCommandEventArgs) Handles GridView1.RowCommand
        If e.CommandName = "dr" Or e.CommandName = "addrow" Then
            Dim str_commandName As String = e.CommandName
            Dim BS As Button = CType(e.CommandSource, Button) '先取得命令的來源並轉換成按鈕
            Dim GV_Row As GridViewRow = CType(BS.NamingContainer, GridViewRow) '將Button轉換成GridViewRow就是您所點選的某一列

            If e.CommandName = "dr" Then
                Delete_RowToGrid(GV_Row.RowIndex)
            ElseIf e.CommandName = "addrow" Then
                AddNewRowToGrid()
            End If
        End If
    End Sub

    Sub Delete_RowToGrid(ByVal int_delet_row As Integer)

        If Not ViewState("CurrentTable") Is Nothing Then
            Dim dtCurrentTable As DataTable = Nothing
            dtCurrentTable = CType(ViewState("CurrentTable"), DataTable)

            If dtCurrentTable.Rows.Count > 0 Then
                '將目前的資料寫回DataTable
                For i As Integer = 0 To dtCurrentTable.Rows.Count - 1
                    If i <> int_delet_row Then
                        Dim TextBox1 As TextBox = CType(GridView1.Rows(i).Cells(1).FindControl("TextBox1"), TextBox)
                        Dim TextBox2 As TextBox = CType(GridView1.Rows(i).Cells(1).FindControl("TextBox2"), TextBox)
                        Dim TextBox3 As TextBox = CType(GridView1.Rows(i).Cells(2).FindControl("TextBox3"), TextBox)
                        Dim TextBox4 As TextBox = CType(GridView1.Rows(i).Cells(3).FindControl("TextBox4"), TextBox)

                        dtCurrentTable.Rows(i)("date_start") = TextBox1.Text
                        dtCurrentTable.Rows(i)("date_end") = TextBox2.Text
                        dtCurrentTable.Rows(i)("Columns2") = TextBox3.Text
                        dtCurrentTable.Rows(i)("Columns3") = TextBox4.Text

                    Else
                        '要刪除的資料不紀錄
                    End If

                Next

                dtCurrentTable.Rows(int_delet_row).Delete() '刪除資料列
                If dtCurrentTable.Rows.Count = 0 Then
                    dtCurrentTable.Clear()
                    dtCurrentTable = Nothing
                    dtCurrentTable = SetInitialRow()
                Else
                    ViewState("CurrentTable") = dtCurrentTable
                End If

                GridView1.DataSource = dtCurrentTable
                GridView1.DataBind()
                GridView1.CssClass = "table table-bordered"
            End If
        Else
            Response.Write("ViewState is null")
        End If

        'Set Previous Data on Postbacks
        SetPreviousData()
    End Sub
End Class

2017年7月11日 星期二

ASP.NET GridView 按下按鈕,加入新的資料列

參考資料:C# Adding Dynamic Rows in ASP.Net GridView Control with TextBoxes (這篇是重點)
參考資料:DataColumn.DataType 屬性

我想製作一個功能,就是在GridView下方有一個加入按鈕,按下「加入」按鈕後插入新的資料列,在網路上看到一些資料,是我要的,但它是C#語法,把它翻成VB語法。

test_GridView_addrows.aspx
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="test_GridView_addrows.aspx.vb" Inherits="test_GridView_addrows" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:GridView ID="Gridview1" runat="server" ShowFooter="true" AutoGenerateColumns="false">
            <Columns>
            <asp:BoundField DataField="RowNumber" HeaderText="Row Number" />
            <asp:TemplateField HeaderText="Header 1">
                <ItemTemplate>
                    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Header 2">
                <ItemTemplate>
                    <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Header 3">
                <ItemTemplate>
                     <asp:TextBox ID="TextBox3" runat="server"></asp:TextBox>
                </ItemTemplate>
                <FooterStyle HorizontalAlign="Right" />
                <FooterTemplate>
                 <asp:Button ID="ButtonAdd" runat="server" Text="Add New Row" onclick="ButtonAdd_Click" />
                </FooterTemplate>
            </asp:TemplateField>
            </Columns>
        </asp:GridView>
    </div>
    </form>
</body>
</html>

test_GridView_addrows.aspx.vb
Imports System.Data
Partial Class test_GridView_addrows
    Inherits System.Web.UI.Page

    Private Sub form1_Load(sender As Object, e As EventArgs) Handles form1.Load
        If Not Page.IsPostBack Then
            '自行建立datatabel給GridView
            SetInitialRow()
        End If
    End Sub

    Sub SetInitialRow()
        Dim dt As datatable = Nothing
        dt = New DataTable()
        Dim dr As DataRow = Nothing
        dt.Columns.Add(New DataColumn("RowNumber", System.Type.GetType("System.String")))
        dt.Columns.Add(New DataColumn("Column1", System.Type.GetType("System.String")))
        dt.Columns.Add(New DataColumn("Column2", System.Type.GetType("System.String")))
        dt.Columns.Add(New DataColumn("Column3", System.Type.GetType("System.String")))
        dr = dt.NewRow()
        dr("RowNumber") = 1
        dr("Column1") = String.Empty
        dr("Column2") = String.Empty
        dr("Column3") = String.Empty
        dt.Rows.Add(dr)
        'Store the DataTable in ViewState
        ViewState("CurrentTable") = dt

        Gridview1.DataSource = dt
        Gridview1.DataBind()
    End Sub

    Sub AddNewRowToGrid()
        Dim rowIndex As Integer = 0
        If Not ViewState("CurrentTable") Is Nothing Then
            Dim dtCurrentTable As DataTable = Nothing
            dtCurrentTable = CType(ViewState("CurrentTable"), DataTable)
            Dim drCurrentRow As DataRow = Nothing

            If dtCurrentTable.Rows.Count > 0 Then
                '將目前的資料寫回DataTable
                For i As Integer = 1 To dtCurrentTable.Rows.Count
                    Dim box1 As TextBox = CType(Gridview1.Rows(rowIndex).Cells(1).FindControl("TextBox1"), TextBox)
                    Dim box2 As TextBox = CType(Gridview1.Rows(rowIndex).Cells(2).FindControl("TextBox2"), TextBox)
                    Dim box3 As TextBox = CType(Gridview1.Rows(rowIndex).Cells(3).FindControl("TextBox3"), TextBox)

                    drCurrentRow = dtCurrentTable.NewRow()
                    drCurrentRow("RowNumber") = i + 1

                    dtCurrentTable.Rows(i - 1)("Column1") = box1.Text
                    dtCurrentTable.Rows(i - 1)("Column2") = box2.Text
                    dtCurrentTable.Rows(i - 1)("Column3") = box3.Text

                    rowIndex = rowIndex + 1
                Next
                dtCurrentTable.Rows.Add(drCurrentRow)
                ViewState("CurrentTable") = dtCurrentTable

                Gridview1.DataSource = dtCurrentTable
                Gridview1.DataBind()
            End If
        Else
            Response.Write("ViewState is null")
        End If

        'Set Previous Data on Postbacks
        SetPreviousData()
    End Sub

    Sub SetPreviousData()
        Dim rowIndex As Integer = 0
        If Not ViewState("CurrentTable") Is Nothing Then
            Dim dt As DataTable = Nothing
            dt = CType(ViewState("CurrentTable"), DataTable)
            If dt.Rows.Count > 0 Then
                For i As Integer = 0 To dt.Rows.Count - 1
                    Dim box1 As TextBox = CType(Gridview1.Rows(rowIndex).Cells(1).FindControl("TextBox1"), TextBox)
                    Dim box2 As TextBox = CType(Gridview1.Rows(rowIndex).Cells(2).FindControl("TextBox2"), TextBox)
                    Dim box3 As TextBox = CType(Gridview1.Rows(rowIndex).Cells(3).FindControl("TextBox3"), TextBox)

                    box1.Text = dt.Rows(i)("Column1").ToString()
                    box2.Text = dt.Rows(i)("Column2").ToString()
                    box3.Text = dt.Rows(i)("Column3").ToString()

                    rowIndex = rowIndex + 1
                Next
            End If
        End If
    End Sub
    Protected Sub ButtonAdd_Click(sender As Object, e As EventArgs)
        AddNewRowToGrid()
    End Sub

End Class

2017年7月1日 星期六

ASP.NET 使用TemplateEngine.Docx套件,Word套表產生docx檔

參考資料:
[C#]TemplateEngine.Docx Word產出好工具
GitHub-TemplateEngine.Docx

本篇使用TemplateEngine.Docx套件來達到Word套表,很適合用在固定的格式,當然作法首先要先作好1個Word檔,也就是要套表的格式,再透過程式將資料寫到自己設定好的Word檔中,產生Word docx檔。

作法如下,因為我自己有時候會把一些筆記寫在Word檔(方便還可以截圖),所以我就不把步驟重新寫一次,直接截圖貼圖上來。




Step 8.程式碼部分
Imports System
Imports System.IO
Imports TemplateEngine.Docx

Partial Class test_TemplateEngine
    Inherits System.Web.UI.Page

    Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'法1.套表完後,儲存在TempWord資料夾
        'step1. 設定路徑
        Dim str_temppath As String = String.Empty, str_NewFileName As String = String.Empty
'給套表後的檔案(新的檔案)一個檔名,這裡用 字串_帳號_時間來設定檔名
        str_NewFileName = "table_1060403_" & DateTime.Now.ToString("yyyyMMddHHmmss") & ".docx"
'設定套表完後的檔案暫存位置
        str_temppath = Server.MapPath("~/TempWord/") & str_NewFileName
'拷貝TemplateWord目錄底下的table2.docx檔案 到 TempWord目錄底下
        File.Copy(Server.MapPath("~/TemplateWord/table2.docx"), str_temppath)

        'step2. 設定要填入的資料 Content
        Dim valuesToFill As Content = Nothing
        valuesToFill = New Content()
        valuesToFill.Fields.Add(New FieldContent("YEAR", "106")) '指定YEAR填入的資料是106

        'step3. 儲存變更
        Using OD1 As TemplateProcessor = New TemplateProcessor(str_temppath).SetRemoveContentControls(True)
            OD1.FillContent(valuesToFill)
            OD1.SaveChanges()
        End Using

'============================================================
        ''法2.套表完後,並下載檔案
        ''step1. 設定路徑
        'Dim str_temppath As String = String.Empty, str_NewFileName As String = String.Empty
        ''給套表後的檔案(新的檔案)一個檔名,這裡用 字串_帳號_時間來設定檔名
        'str_NewFileName = "table_1060403_" & DateTime.Now.ToString("yyyyMMddHHmmss") & ".docx"
        ''設定套表完後的檔案暫存位置
        'str_temppath = Server.MapPath("~/TempWord/") & str_NewFileName
        ''拷貝TemplateWord目錄底下的table2.docx檔案 到 TempWord目錄底下
        'File.Copy(Server.MapPath("~/TemplateWord/table2.docx"), str_temppath)

        ''step2. 設定要填入的資料 Content
        'Dim valuesToFill As Content = Nothing
        'valuesToFill = New Content()
        'valuesToFill.Fields.Add(New FieldContent("YEAR", "106")) '指定YEAR填入的資料是106

        ''step3. 儲存變更
        'Using OD1 As TemplateProcessor = New TemplateProcessor(str_temppath).SetRemoveContentControls(True)
        '    OD1.FillContent(valuesToFill)
        '    OD1.SaveChanges()
        'End Using

        ''step4. 檔案下載
        'Dim buff() As Byte = Nothing
        'Response.Clear()
        'Response.ContentType = "application/octet-stream"
        'Response.AddHeader("content-disposition", "attachment;filename=" & str_NewFileName)
        'buff = File.ReadAllBytes(str_temppath)
        'File.Delete(str_temppath) '刪除檔案
        'Response.BinaryWrite(buff)
        'Response.End()
    End Sub
End Class

Step 9.最後請執行程式,看是否成功。

補充:
在開發專案過程中,遇到ListItem與TemplateEngine.Docx會有所衝突,例如以下這行程式碼:
DropDownList1.Items.Insert(0, New ListItem("請選擇項目", "0"))
看似很正常,但是Visual Studio就會針對New ListItem發現錯誤,錯誤代碼BC30516。
你只需要拿掉Imports TemplateEngine.Docx或者要明確的指定Content型態類別
再將原本這段
Dim valuesToFill As Content = Nothing
valuesToFill = New Content()
valuesToFill.Fields.Add(New FieldContent("YEAR", "106"))
程式碼改為
Dim valuesToFill As TemplateEngine.Docx.Content = Nothing
valuesToFill = New TemplateEngine.Docx.Content()
valuesToFill.Fields.Add(New TemplateEngine.Docx.FieldContent("YEAR", "106")) '學年度

2017年6月25日 星期日

ASP.NET 使用JS達到Shift鍵加滑鼠左鍵讓Table中的CheckBox連續選取

這個需求是要模仿電子信箱中的CheckBox(我是參考GMail),勾選了第1筆之後,Shift鍵+滑鼠左鍵勾選第2筆,可以勾選我們要的多筆資料,稱這種功能為「連續選取」(我沒說錯吧)。
如果有想嘗試的人,可以先去我的前一篇(ASP.NET Table中的刪除按鈕,顯示2次提示訊息)複製SQL CREATE TABLE指令先建立資料表,所以後端程式碼我就不貼出來了,因為差不多一樣只是這次的重點在JavaScript怎麼達到連續選取的功能,說明都寫在註解中

test_gv_checkbox.aspx
前端
<%@ Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/MasterPage1.master" CodeBehind="test_gv_checkbox.aspx.vb" Inherits="test_gridview_dialog.test_gv_checkbox" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
        <style type="text/css">
        /*test_gv_dialog.aspx 只要是要使用在這個網頁的css都寫在此處*/
        /*設定CheckBox大小,套用的對象有2個
          1.只要是input的checkbox都套用。
          2.因為GridView的CheckBox CssClass屬性有設定CSS,經過轉譯後CheckBox會被span標籤包起來,
            所以只要是span標籤class是rowcb底下的CheckBox都套用。
        */
        input[type="checkbox"], span[class="rowcb"]>input[type="checkbox"]{
          width: 20px;
          height: 20px;
        }
    </style>
    <script type="text/javascript">
        //test_gv_dialog.aspx JavaScript只要是要使用在這個網頁的JavaScript都寫在此處
        var shiftkeydown = false; //紀錄使用者目前有沒有按下Shift鍵
        $(document).ready(function () {
            //只要是CSS類別名稱為GV1_headcb,底下的CheckBox就註冊change事件
            $('.GV1_headcb > input[type="checkbox"]').change(function () {
                var bool_change;
                bool_change = this.checked; //取得自己勾選狀態
                //table底下的tbody底下的tr CheckBox透過each(類似迴圈),將table中所有的CheckBox設定為勾選或取消勾選
                $('#<%=GridView1.ClientID %> > tbody > tr input[type="checkbox"]').each(function () {
                    $(this).prop('checked', bool_change); //設定CheckBox狀態
                });
            });
            //註冊keydown keyup事件,function名稱為listening_for_shift
            $(document).on('keydown keyup', listening_for_shift);
            //為GridView註冊change事件,對象是所有的CheckBox
            $('#<%=GridView1.ClientID %>').on('change', 'input[type="checkbox"]', function () {

                var this_checked_index = $(this).closest('tr').index(); //取得使用者勾選哪一個checkbox tr index
                var str_hfval=$('#<%=HF_cbindex.ClientID%>').val(); //取得使用者上一次點了哪一個CheckBox

                //當使用者按下shift 且 大於0(不包含GridView table head中CheckBox)
                if (shiftkeydown == true && this_checked_index > 0) {
                    var before_index;
                    if (str_hfval != '') {
                        var re = /^[0-9]+$/;
                        if (!re.test(str_hfval)) {
                            return false; //不是數字就中斷
                        };
                        before_index = parseInt(str_hfval);
                        if (before_index < this_checked_index) {
                            for (var i = before_index; i <= this_checked_index; i++) {
                                $('#<%=GridView1.ClientID %>').find('tr:eq(' + i + ') input[type="checkbox"]').prop('checked', true);
                            };
                        } else if (before_index > this_checked_index) {
                            for (var i = this_checked_index; i <= before_index; i++) {
                                $('#<%=GridView1.ClientID %>').find('tr:eq(' + i + ') input[type="checkbox"]').prop('checked', true);
                            };
                        };
                    };
                };

                if (this_checked_index > 0){
                    $('#<%=HF_cbindex.ClientID%>').val(this_checked_index); //紀錄目前使用者勾選哪一個checkbox tr index
                };
            });
        });
        function listening_for_shift(e) {
            if (e.keyCode == 16) {
                if (e.type === "keydown") {
                    //alert('down shift');
                    shiftkeydown = true;
                }
                if (e.type === "keyup") {
                    //alert('no shift');
                    shiftkeydown = false;
                }
            }
        };
    </script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <div class="container">
        <div class="row cust_blank1">
            <div class="col-xs-12">
                仿電子信箱中的CheckBox,勾選了第1筆之後,Shift鍵+滑鼠左鍵勾選第2筆,可以勾選我們要的多筆資料
                <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
                    <Columns>
                        <asp:TemplateField HeaderText="">
                            <HeaderTemplate>
                                <asp:CheckBox ID="GV1_headcb" runat="server" CssClass="rowcb GV1_headcb"/>
                            </HeaderTemplate>
                            <ItemTemplate>
                                <asp:CheckBox ID="CheckBox1" runat="server" CssClass="rowcb" />
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:TemplateField HeaderText="編號">
                            <ItemTemplate>
                                <%# Eval("ser_no")%>
                                <asp:HiddenField ID="HF_serno" runat="server" Value='<%# Eval("ser_no")%>' />
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:TemplateField HeaderText="標題">
                            <ItemTemplate>
                                <%# Eval("title")%>
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:TemplateField HeaderText="內容">
                            <ItemTemplate>
                                <%# Eval("cont")%>
                            </ItemTemplate>
                        </asp:TemplateField>
                    </Columns>
                    <EmptyDataTemplate>
                        <asp:Label ID="GV_Empty" runat="server" Text="目前無資料"></asp:Label>
                    </EmptyDataTemplate>
                </asp:GridView>
                <asp:HiddenField ID="HF_cbindex" runat="server" />
            </div>
        </div>
    </div>
</asp:Content>

說明:重點要記錄使用者第1次點了哪一個CheckBox,當使用者點了第2次時,就可以知道使用者點的範圍到哪裡,來作連續勾選的動作。

以上如有錯誤請指證,謝謝。

ASP.NET Table中的刪除按鈕,顯示2次提示訊息

以往要在GridView要刪除資料時,都會使用javascript confirm來問使用者是否確定要刪除資料,這次的需求是要跟使用者確認兩次,第一次詢問使用者「您確定要刪除這筆資料嗎?刪除後將無法還原!」,當按下確定後,第二次再次詢問使用者「真的確定要刪除這筆資料?」,按下確定刪除後,就真的刪除資料,所以這次要使用的是bootstrap dialog。

Step 1.首先到這個GitHub下載bootstrap3-dialog套件

Step 2.我會使用到jquery-1.11.3.js檔,也請先準備好,並且將下載好的dialog放到專案中。
說明:我的css目錄中有一個檔案名為bootstrap-dialog_vc.css,它的作用主要是讓訊息框可以垂直置中(請點我),因為預設dialog是不會幫我們作垂直置中的。
bootstrap-dialog_vc.css檔,內容如下:
.modal {
    text-align: center;
    padding: 0 !important;
}
.modal:before {
    content: '';
    display: inline-block;
    height: 100%;
    vertical-align: middle;
    margin-right: -4px;
}
.modal-dialog {
    display: inline-block;
    text-align: left;
    vertical-align: middle;
}

Step 3.我在寫ASP.NET WebForm的時候,都會習慣使用Master Page,所以請建立一個Master Page,名稱使用預設的名稱即可或自行定義也可以,程式碼如下:
<%@ Master Language="VB" CodeFile="MasterPage1.master.vb" Inherits="MasterPage1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head runat="server">
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>test_gridview_dialog</title>
    <link rel="stylesheet" href="css/bootstrap.min.css" />
    <script src="js/jquery-1.11.3.js"></script>
    <script src="js/bootstrap.min.js"></script>
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    <asp:ContentPlaceHolder id="head" runat="server">
    </asp:ContentPlaceHolder>
    <style type="text/css">
        /*MasterPage1 css*/
        body {
        background-color:#ffffff; /*背景顏色*/
        }
    </style>
    <script type="text/javascript">
        //MasterPage1 JavaScript
    </script>
  </head>
  <body>
    <form id="form1" runat="server">
        <asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
     
        </asp:ContentPlaceHolder>
    </form>
  </body>
</html>

Step 5.建立資料表,待會測試要用,以下是sql指令,方便讓大家建立資料表
以下為CREATE TABLE指令:
USE [test1]--這裡改成自己測試的資料庫
GO
/****** Object:  Table [dbo].[test_table1]    Script Date: 06/25/2017 19:16:26 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[test_table1](
[ser_no] [char](4) NOT NULL,
[title] [varchar](10) NULL,
[cont] [varchar](10) NULL,
 CONSTRAINT [PK_test_table1] PRIMARY KEY CLUSTERED
(
[ser_no] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO

以下為INSERT指令:
INSERT [dbo].[test_table1] ([ser_no], [title], [cont]) VALUES (N'0001', N'標題01', N'內容01')
INSERT [dbo].[test_table1] ([ser_no], [title], [cont]) VALUES (N'0002', N'標題02', N'內容02')
INSERT [dbo].[test_table1] ([ser_no], [title], [cont]) VALUES (N'0003', N'標題03', N'內容03')
INSERT [dbo].[test_table1] ([ser_no], [title], [cont]) VALUES (N'0004', N'標題04', N'內容04')
INSERT [dbo].[test_table1] ([ser_no], [title], [cont]) VALUES (N'0005', N'標題05', N'內容05')

Step 4.再來建立名為test_gv_dialog.aspx的網頁,程式碼如下:
前端:
<%@ Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/MasterPage1.master" CodeBehind="test_gv_dialog.aspx.vb" Inherits="test_gridview_dialog.test_gv_dialog" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
    <link rel="stylesheet" href="css/bootstrap-dialog.min.css" />
    <link rel="stylesheet" href="css/bootstrap-dialog_vc.css" />
    <script src="js/bootstrap-dialog.min.js"></script>
    <style type="text/css">
        /*test_gv_dialog.aspx 只要是要使用在這個網頁的css都寫在此處*/
    </style>
    <script type="text/javascript">
        //test_gv_dialog.aspx JavaScript只要是要使用在這個網頁的JavaScript都寫在此處
        function delmessbox(int_row,str_mess) {
            BootstrapDialog.show({
                title: '確認是否刪除',
                message: '您確定要刪除「編號' + str_mess + '」這筆資料嗎?<br/>刪除後將無法還原!',
                buttons: [{
                    label: '確定',
                    action: function (dialog) {
                        delmessbox_again1(int_row, str_mess);
                        dialog.close();
                    }
                }, {
                    label: '取消',
                    action: function (dialog) {
                        dialog.close();
                    }
                }]
            });
            //因為使用bootstrap-dialog關係,當使用者按下按鈕後,呼叫delmessbox方法,會執行BootstrapDialog.show,
            //但必須要注意,程式它並不會停在BootstrapDialog.show,等待使用者回傳哪一個動作(確認或取消),
            //程式還是會繼續往下執行,如果沒有回傳false則會繼續執行Bdel按鈕中的OnClick事件中的下一個function,一樣會執行刪除。
            return false;
        };
        function delmessbox_again1(int_row, str_mess) {
            BootstrapDialog.show({
                title: '再次確認',
                message: '真的確定要刪除「編號' + str_mess + '」這筆資料?',
                buttons: [{
                    label: '確定刪除',
                    action: function (dialog) {
                        dialog.close();
                        con_exedel(int_row);
                    }
                }, {
                    label: '取消刪除',
                    action: function (dialog) {
                        dialog.close();
                    }
                }]
            });
        };
        function con_exedel(int_row) {
            //這裡將會把GridView所有的Button該呼叫哪一個function寫在這裡
            switch (int_row) {
                <%=str_deljs.ToString()%>
                <% str_deljs.Clear() : str_deljs = Nothing%>
            };
        };
    </script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <div class="container">
        <div class="row cust_blank1">
            <div class="col-xs-12">
                <span id="span_mess" runat="server"></span>
                <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
                    <Columns>
                        <asp:TemplateField HeaderText="">
                            <ItemTemplate>
                                <asp:Button ID="Bdel" runat="server" Text="刪除" CommandName="de" CssClass="btn btn-default"/>
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:TemplateField HeaderText="編號">
                            <ItemTemplate>
                                <%# Eval("ser_no")%>
                                <asp:HiddenField ID="HF_serno" runat="server" Value='<%# Eval("ser_no")%>' />
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:TemplateField HeaderText="標題">
                            <ItemTemplate>
                                <%# Eval("title")%>
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:TemplateField HeaderText="內容">
                            <ItemTemplate>
                                <%# Eval("cont")%>
                            </ItemTemplate>
                        </asp:TemplateField>
                    </Columns>
                    <EmptyDataTemplate>
                        <asp:Label ID="GV_Empty" runat="server" Text="目前無資料"></asp:Label>
                    </EmptyDataTemplate>
                </asp:GridView>
            </div>
        </div>
    </div>
</asp:Content>

後端:
Imports System.Data.SqlClient

Public Class test_gv_dialog
    Inherits System.Web.UI.Page
    Dim str_sqlconn As String = "Server=127.0.0.1;uid=test;pwd=test;Database=test1" '可以寫在web.config
    Dim str_sql As String = String.Empty
    Dim def_dt As DataTable = Nothing
    Dim int_gv_row As Integer = 0
    Public str_deljs As StringBuilder = Nothing
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not Page.IsPostBack Then
            str_sql = "select * from test_table1"
            def_dt = queryDataTable2(str_sql)
            GridView1.DataSource = def_dt
            GridView1.DataBind()
            GridView1.CssClass = "table table-bordered"
            def_dt.Clear() : def_dt.Dispose() : def_dt = Nothing
        End If
    End Sub

    Function queryDataTable2(ByVal sql_str As String, Optional ByVal pv As String = Nothing, Optional ByVal sqlvalue_p() As String = Nothing) As DataTable
        Dim sql_p() As String = Nothing
        If Not pv Is Nothing Then
            sql_p = pv.Split(",") 'sql字串中的參數
        End If

        Dim ds As New DataSet()
        Using conn As New SqlConnection(str_sqlconn)
            Dim command As SqlCommand = New SqlCommand(sql_str, conn)

            If Not pv Is Nothing And Not sqlvalue_p Is Nothing Then
                Dim x_end As Integer = sql_p.Length - 1
                For x As Integer = 0 To x_end
                    If command.Parameters.Contains(sql_p(x)) Then
                        command.Parameters(sql_p(x)).Value = sqlvalue_p(x)
                    Else
                        command.Parameters.AddWithValue(sql_p(x), sqlvalue_p(x)) '讓ADO.NET自行判斷型別轉換
                    End If
                Next
            End If

            Dim da As New SqlDataAdapter()
            da.SelectCommand = command

            da.Fill(ds)

            command.Cancel()
            command.Dispose()
        End Using
        If ds.Tables.Count > 0 Then
            Return ds.Tables(0)
        Else
            Return New DataTable()
        End If
    End Function

    Private Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
        If e.Row.RowType = DataControlRowType.Header Then
            '設定欄位Class
            e.Row.CssClass = "bg-primary"
            e.Row.Cells(0).CssClass = "col-xs-1 col-md-1"
            e.Row.Cells(1).CssClass = "col-xs-1 col-md-1"
            e.Row.Cells(2).CssClass = "col-xs-1 col-md-1"
            e.Row.Cells(3).CssClass = "col-xs-1 col-md-1"

            str_deljs = New StringBuilder()
        End If
        If e.Row.RowType = DataControlRowType.DataRow Then
            Dim Bdel As Button = CType(e.Row.FindControl("Bdel"), Button)
            If Not (Bdel Is Nothing) Then
                '在Bdel按鈕中,加入onclick事件delmessbox方法
                Bdel.Attributes.Add("onclick", "javascript:return delmessbox(" & int_gv_row & ",'" & CType(e.Row.DataItem, DataRowView).Item("ser_no").ToString() & "');" & ClientScript.GetPostBackEventReference(Bdel, "").ToString() & ";")
            End If
            str_deljs.Append("case " & int_gv_row & ":" & ClientScript.GetPostBackEventReference(Bdel, "").ToString() & ";break;")
            int_gv_row = int_gv_row + 1
        End If
    End Sub

    Private Sub GridView1_RowCommand(sender As Object, e As GridViewCommandEventArgs) Handles GridView1.RowCommand
        If e.CommandName = "de" Then
            Dim str_commandName As String = e.CommandName
            Dim BS As Button = CType(e.CommandSource, Button) '先取得命令的來源並轉換成按鈕
            Dim GV_Row As GridViewRow = CType(BS.NamingContainer, GridViewRow) '將Button轉換成GridViewRow就是您所點選的某一列

            str_sql = "delete test_table1 where ser_no=@ser_no"
            '建議HF_serno的Value要事先先加密,當使用按下按鈕之後,再解密這樣會比較安全
            Dim str_serno As String = CType(GridView1.Rows(GV_Row.RowIndex).FindControl("HF_serno"), HiddenField).Value
            Dim int_enq As Integer = 0
            Using conn As New SqlConnection(str_sqlconn)
                conn.Open()

                Dim command As SqlCommand = New SqlCommand(str_sql, conn)

                If command.Parameters.Contains("@ser_no") Then
                    command.Parameters("@ser_no").Value = str_serno
                Else
                    command.Parameters.AddWithValue("@ser_no", str_serno) '讓ADO.NET自行判斷型別轉換
                End If

                int_enq = command.ExecuteNonQuery()

                command.Cancel() 'SqlDataReader要close前,要先Cancel SqlCommand
                command.Dispose()

                conn.Close()
            End Using
            If int_enq = 1 Then
                Me.span_mess.InnerHtml = "<span style=" & Chr(34) & "color:blue;" & Chr(34) & ">系統於 " & Date.Now.ToString("yyyy/MM/dd HH:mm:ss") & " 已刪「編號:" & str_serno & "」這筆資料。</span>"
                '刪除成功,重新讀取資料
                str_sql = "select * from test_table1"
                def_dt = queryDataTable2(str_sql)
                GridView1.DataSource = def_dt
                GridView1.DataBind()
                GridView1.CssClass = "table table-bordered"
            Else
                Me.span_mess.InnerHtml = "<span style=" & Chr(34) & "color:red;" & Chr(34) & ">系統於 " & Date.Now.ToString("yyyy/MM/dd HH:mm:ss") & " 「編號:" & str_serno & "」刪除失敗。</span>"
            End If
        End If
    End Sub
End Class

執行結果:


以上,說明我寫在註解中,如有錯誤的地方,請指證,謝謝。