none
[VB2008] DataGridView四問 RRS feed

  • 問題

  • 想請教各位大大
    小弟這陣子在寫VB程式
    有幾個疑問想請教一下
    1.在DataGridView中,如何將選擇列的資料顯示在視窗中??(可在資料列上雙點兩下滑鼠左鍵或者點選資料列前方的CheckBox後按下"編輯"按鍵時,出現視窗顯示該列資料)
    2.如何在DataGridView中刪除多列的選擇資料??(每列前方有CheckBox欄位可供選擇)(有看過使用Collection的,但不是很懂)
    3.如何將DataGridView中的資料寫入Excel中,若Excel檔案中已經有資料者,則加以覆蓋??
    4.DataGridView中有一個設定可以使得資料列的最後一列不會產生空白列,之前有在這邊看過,但現在爬文都沒找到,不知哪為大大還記得該項設定呢??

    上述四個問題還請各位大大協助一下
    小弟寫習慣VC++ and Java了
    突然轉到VB實在是有點不習慣
    有勞各位大大了...

    開發環境:WIN XP SP3+Visual Studio 2008
    2009年3月31日 下午 03:14

解答

  • 風箏:
           1.你是想要把所選的列之的資料拉到另一個視窗嗎?那就是事件(或許是按個Button的Click事件 or somthing others)中撰寫
              (1)直接用DataGridview1.Rows(看哪個列).Item(看哪個欄)把值抓出來
              (2)如果是有Selected屬性,也可以用For each DataGridViewRow in DataGridView1.SelectedRows.Item(看哪個欄)
              (3)如果要抓CurrentRow,就用DataGridView1.CurrentRow.Item(看哪個欄)
              (4)如果你要從DataTable來抓,可以用先前的DataTable.Select方法,比如先用For each DataGridViewRow in DataGridView1.SelectedRows.Item(0) , 故DataTable.Select的條件就是那個值了,就可以在DataTable內選出符合條件的列,然後可以取值
               (4-1)DataRow取值可以用ItemArray屬性取得一個Object形態的陣列,陣列內就會有該Row的每個值
               (4-2)累一點的方法當然是Row.Item(看哪個欄),然後一個個取
               關於DataRow.ItemArray 可以參考[資料列的複製問題]
               http://social.msdn.microsoft.com/Forums/zh-TW/232/thread/a8b011ba-8680-4846-b1a3-4de3e10a70b1
       
              [有關資料表的排序問題]
              http://social.msdn.microsoft.com/Forums/zh-TW/232/thread/ab58880e-812c-4cb1-b77c-3b3dd3bacd19
            2.刪除多個資料列是否也需要同時更新資料來源?
              (1)如果要,你可以參考之前[刪除DataSet記錄的問題]的討論
                  http://social.msdn.microsoft.com/Forums/zh-TW/232/thread/0087a345-e097-4def-a7b6-49394d7a2b9d
              (2)如果不要,那就一樣,先找出要刪除的鍵值<同1 .(4) >的說法,然後找出Row然後用DataRowCollection.Remove或是DataRowCollection.RemoveAt <這方法要找到Row Index> ,先前我們不是談過BindingSource嗎?當你把資料從DataTable刪除後,一樣呼叫BindingSource.ResetBindings(False)方法就OK囉 <如果你有用BindingSource的話>

             3.這個可讓我露餡兒了,我沒想過把資料存在Excel的事情,我有空試試看再告訴你.

             4.空白列是因為你有設定DataGridView.AllowUserToAddRows為True ,也就是有啟用新增的功能,把它設為False應該就行了
          
          
             你先玩玩,有問題我們再繼續討論


               

                  
              
             
    • 已標示為解答 風箏惡魔 2009年4月1日 上午 01:02
    2009年4月1日 上午 12:54
    版主
    1. 可以在DataGirdView的CellMouseDoubleClick等事件中撰寫你所要回應使用者的程式碼。
    2. 按使用者按下刪除時跑迴圈去檢查每一列中CheckBox的checked屬性。
    3. 參考http://social.msdn.microsoft.com/forums/zh-TW/233/thread/770b6546-315d-45c3-8c49-0b89cedf70ee/http://www.codeplex.com/ExportToExcel,其中後者有現成的元件。
    4. 設定DataGridview.AllowUsertoAddRows為flase。

    2009年4月1日 上午 01:00

所有回覆

  • 風箏:
           1.你是想要把所選的列之的資料拉到另一個視窗嗎?那就是事件(或許是按個Button的Click事件 or somthing others)中撰寫
              (1)直接用DataGridview1.Rows(看哪個列).Item(看哪個欄)把值抓出來
              (2)如果是有Selected屬性,也可以用For each DataGridViewRow in DataGridView1.SelectedRows.Item(看哪個欄)
              (3)如果要抓CurrentRow,就用DataGridView1.CurrentRow.Item(看哪個欄)
              (4)如果你要從DataTable來抓,可以用先前的DataTable.Select方法,比如先用For each DataGridViewRow in DataGridView1.SelectedRows.Item(0) , 故DataTable.Select的條件就是那個值了,就可以在DataTable內選出符合條件的列,然後可以取值
               (4-1)DataRow取值可以用ItemArray屬性取得一個Object形態的陣列,陣列內就會有該Row的每個值
               (4-2)累一點的方法當然是Row.Item(看哪個欄),然後一個個取
               關於DataRow.ItemArray 可以參考[資料列的複製問題]
               http://social.msdn.microsoft.com/Forums/zh-TW/232/thread/a8b011ba-8680-4846-b1a3-4de3e10a70b1
       
              [有關資料表的排序問題]
              http://social.msdn.microsoft.com/Forums/zh-TW/232/thread/ab58880e-812c-4cb1-b77c-3b3dd3bacd19
            2.刪除多個資料列是否也需要同時更新資料來源?
              (1)如果要,你可以參考之前[刪除DataSet記錄的問題]的討論
                  http://social.msdn.microsoft.com/Forums/zh-TW/232/thread/0087a345-e097-4def-a7b6-49394d7a2b9d
              (2)如果不要,那就一樣,先找出要刪除的鍵值<同1 .(4) >的說法,然後找出Row然後用DataRowCollection.Remove或是DataRowCollection.RemoveAt <這方法要找到Row Index> ,先前我們不是談過BindingSource嗎?當你把資料從DataTable刪除後,一樣呼叫BindingSource.ResetBindings(False)方法就OK囉 <如果你有用BindingSource的話>

             3.這個可讓我露餡兒了,我沒想過把資料存在Excel的事情,我有空試試看再告訴你.

             4.空白列是因為你有設定DataGridView.AllowUserToAddRows為True ,也就是有啟用新增的功能,把它設為False應該就行了
          
          
             你先玩玩,有問題我們再繼續討論


               

                  
              
             
    • 已標示為解答 風箏惡魔 2009年4月1日 上午 01:02
    2009年4月1日 上午 12:54
    版主
    1. 可以在DataGirdView的CellMouseDoubleClick等事件中撰寫你所要回應使用者的程式碼。
    2. 按使用者按下刪除時跑迴圈去檢查每一列中CheckBox的checked屬性。
    3. 參考http://social.msdn.microsoft.com/forums/zh-TW/233/thread/770b6546-315d-45c3-8c49-0b89cedf70ee/http://www.codeplex.com/ExportToExcel,其中後者有現成的元件。
    4. 設定DataGridview.AllowUsertoAddRows為flase。

    2009年4月1日 上午 01:00
  • Bill大
    咱們先討論第2個問題
    小弟剛剛看了一下您貼的連結
    他是針對SQL去做刪除動作的
    但小弟目前是針對Excel檔案去做刪除的動作

    目前的想法是:
    1.先能盼讀到DataGridView的第一欄位(CheckBox)的值是否為true[ChekBox欄位在設計時利用DataGridView的加入資料行所產生的,Name為Check_Column]
    2.若CheckBox的值為true則針對該列資料做刪除的動作
    3.刪除後將DataGridView中顯示的資料存回Excel檔中(完全覆蓋寫入)

    小弟目前一直無法讀取到CheckBox的值
    不知該如何讀取呢??
    2009年4月1日 上午 02:19
  • Terry大大
    小弟剛剛有連上您提供的連結去爬文
    想請教一下
    抓下來的ExportToExcel的dll檔
    要怎麼使用呢??(沒用過)
    另...看不到該dll檔是否適用在Excel 2007的檔案格式中...
    2009年4月1日 上午 02:22
  • 先講一個東西,唉,我真糊塗!
     DataRow取值是用DataRow.Item沒錯
    不過DataGridViewRow取值要用 .Cells(看是哪一格).Value
    你的CheckBox所在的Column應該是DataGridViewCheckBoxColumn,沒錯吧.
    所以先
    Dim bIsChecked as Boolean
    讀現在這一列
    bIsChecked=DataGridView1.CurrentRow.Cells("這邊是DataGridView1的Column Name"也可用Index值).Value 
    讀某一列
    bIsChecked=DataGridView1.Rows(看要哪一列).Cells("這邊是DataGridView1的Column Name"也可用Index值).Value 


    2009年4月1日 上午 02:39
    版主
  • 剛剛try了一下
    先利用MessageBox嘗試將取得的值show出來
    結果是...不會顯示
    code如下
        Private Sub DeleteSong_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

            Dim bIsChecked As Boolean
            bIsChecked = DataView.CurrentRow.Cells(0).Value
            MessageBox.Show(DataView.CurrentRow.Cells(0).Value)

        End Sub

    理論上Cells(0)取出來的應該為CheckBox的值(False or True)
    但...沒有捏...

    2009年4月1日 上午 03:05
  • 我找到問題點了
    在於當CheckBox為true時
    但該列資料並未完全選取
    所以導致無法判讀Cells(0)

    思考如何設定整列選取...

    2009年4月1日 上午 03:15
  •    不會吧..這個我測過,沒有問題啊,你用Column Name代替Index試試看
    2009年4月1日 上午 03:15
    版主
  • 現在可以取出Cells(0)的值了
    接下來傲嘗試刪除一列資料...
    code如下:
        Private Sub DeleteSong_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DeleteSong_Button.Click

            Dim selectCheck As Boolean
            selectCheck = DataView.CurrentRow.Cells(0).Value
            DataView.Rows.Remove(DataView.CurrentRow)
            sBS.ResetBindings(False)

        End Sub

    目前是可以刪除列資料
    但是不知道該怎麼用CheckBox的值丟進去判斷該列是否選取

    2009年4月1日 上午 03:23
  • 我錯了..原來手動自行增加的CheckBox會有問題
    因為一開始會沒有初始值,所以手動設定的在沒點過之前會出現空白
    有個先期的解決方法,就是只要不是True就是False..
    我再想想看怎麼給這個欄位初始值

    行了行了,我好呆,用For Each就好啦
    下面是給定初始值的example
      Dim myDatatable As New DataTable
       Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            MessageBox.Show(DataGridView1.CurrentRow.Cells("CHK").Value)
        End Sub

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            myDatatable.Columns.Add("TTT")
            Dim i As Integer
            For i = 0 To 9
                Dim myNewRow As DataRow = myDatatable.NewRow
                myNewRow.Item(0) = i
                myDatatable.Rows.Add(myNewRow)
            Next

            DataGridView1.DataSource = myDatatable
           '在指定資料來源給DataGridView1後設定初始值
            Dim xRow As DataGridViewRow
            For Each xRow In DataGridView1.Rows
                xRow.Cells("CHK").Value = False
            Next

        End Sub

    2009年4月1日 上午 03:33
    版主
  • 小弟目前把code改寫如下:

        Private Sub DeleteSong_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DeleteSong_Button.Click

            Dim selectCheck As Boolean
            selectCheck = DataView.CurrentRow.Cells(0).Value

            If (selectCheck = True) Then
                DataView.Rows.Remove(DataView.CurrentRow)
            End If

            sBS.ResetBindings(False)

        End Sub

    這樣就可以判斷CurrentRow的CheckBox是否選取
    再加以刪除
    以免刪除錯誤的資料列...

    但要怎麼多列刪除呢??

    2009年4月1日 上午 03:45
  • 我發現啊,如果想要從DataGridView上動歪腦筋多列刪可能會很麻煩,因為你用迴圈刪的話
    ,你每刪掉一筆記錄DataGridView的Index就會改變比如本來這個DataGridViewRow的Index是5
    你刪掉4,就會導致原來Index是5的變成4,然後就會亂成一團
    我認為還是回歸到去找出DataTable所對應的列,把資料從DataTable中刪掉會比較好
    2009年4月1日 上午 04:10
    版主
  • 嗯...
    這個我再想想
    或許可以另外設定一個變數去計算刪除的次數deleteCounter
    再將Index跟deleteCounter相減成為新的Index
    或許這樣可行...(有空再試試看)

    小弟現在碰到一個問題
    將DataGridView的資料寫入txt檔案時
    出現一個疑問
    code如下:
        Private Sub SaveSong_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SaveSong_Button.Click

            Dim txtFileName As String

            Dim fileRow As DataRow
            Dim fileColumn As DataColumn
            Dim saveTable As DataTable

            txtFileName = "文字檔(*.txt)|*.txt"
            SaveDataBase.Filter = txtFileName
            SaveDataBase.FilterIndex = 1
            SaveDataBase.InitialDirectory = "C:\"
            SaveDataBase.RestoreDirectory = True

            If SaveDataBase.ShowDialog() = DialogResult.OK Then
                txtFileName = SaveDataBase.FileName
            End If

            Dim saveFileName As FileStream = New FileStream(txtFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite)

            Using FileSave As StreamWriter = New StreamWriter(saveFileName, System.Text.Encoding.Unicode)
                For Each saveTable In xxxxxx
                    For Each colobject In saveTable.Columns
                        FileSave.Write(colobject.caption & ";")
                    Next
                    FileSave.WriteLine()
                    For Each fileRow In saveTable.Rows

                        For Each fileColumn In saveTable.Columns

                            FileSave.Write(fileRow(fileColumn).ToString() & ";")

                        Next fileColumn

                        FileSave.WriteLine()

                    Next fileRow
                Next saveTable

            End Using

        End Sub

    在粗體底線的部分
    是要連結到DataSet的
    但...
    目前是採用Bill大大提供的方式將資料導入DataGridView的
    這...該怎麼寫呢??

    2009年4月1日 上午 08:17
  • 風箏:
            如果你只有一個Table ,
    那  For Each saveTable In xxxxxx這個迴圈就是不必要的,
    我想原始作者要這樣的原因,應該是在他的Dataset中有多個DataTable要存入
    2009年4月1日 下午 01:06
    版主
  • Bill大:
    如果去除For Each saveTable In xxxxxx這個迴圈
    會出現一個問題
    就是下一行的saveTable會在指定值前就使用造成null的問題耶...
    2009年4月1日 下午 02:51
  • 因為saveTable是空的吧,看起來是要把saveTable的資料倒出去
    所以要先把DataGridview的資料倒給saveTable
    假設DataGridView1的DataSource為DataTable1 <--要設成全域了
    saveTable=DataTable1.Copy
    或者你就乾脆用來源,也就是DataTable1取代saveTable

    2009年4月1日 下午 03:56
    版主
  • 我是採用 copy的方式來處理的
    但現在碰到了很奇怪的問題
    就是若我先將DataGridView的資料存成txt檔後
    再進行DataGridView的資料修改
    然後另存一個txt檔
    此時會出現"無法經由資料列存取已刪除的資料列資訊。"

    2009年4月1日 下午 11:03
  • 2009年4月2日 上午 01:41
    版主

  • 看了很久...研究了很久
    還是不太懂
    因為在刪除資料後
    要怎麼去更新DataTable的值呢??
    表面上看到的是已經更新了...
    但後端的資料庫卻沒有動作...
    所以無法存成txt檔...

    2009年4月2日 上午 03:18
  •    之前不是叫你參考之前[刪除DataSet記錄的問題]的討論
                  http://social.msdn.microsoft.com/Forums/zh-TW/232/thread/0087a345-e097-4def-a7b6-49394d7a2b9d

       這就有提到如何利用SqlDataAdapter.Update  來更新資料庫
       你可以先用SQL資料庫玩一玩這個範例,稍微體會一下
    2009年4月2日 上午 04:49
    版主
  • 剛剛很努力的研究了一下
    發現...
    DataSet==>BindingSource==>DataGridView.DataSource
    在做刪除動作後
    對DataSet做Update
    是這樣嗎??
    2009年4月2日 上午 07:17
  • Yes...就是這樣一回事
    Bindinsource只是一個中介的物體

    2009年4月2日 上午 08:26
    版主
  • 以下是目前修改的code
    =========宣告變數部分======
        Dim MyOleDb_cn As New OleDb.OleDbConnection
        Dim MyOleDb_cmd As New OleDb.OleDbCommand
        Dim MyData As OleDb.OleDbDataAdapter
        Public MDS As New DataSet

        Public sBS As New BindingSource
        Public mDT As New DataTable

    =========載入Excel部分======
            MyOleDb_cn = New OleDb.OleDbConnection("Provider=Microsoft.ACE.OleDb.12.0;" & "Data Source=" & Open_File & ";" & "Extended Properties=Excel 12.0")
            MyOleDb_cmd = New OleDb.OleDbCommand("Select * from [sheet1$]", MyOleDb_cn)
            MyData = New OleDb.OleDbDataAdapter(MyOleDb_cmd)
            MyData.Fill(MDS)
            sBS.DataSource = MDS.Tables(0)
            DataView.DataSource = sBS
            sBS.ResetBindings(False)
            'DataView.DataSource = MDS.Tables(0).DefaultView

            Dim selectCheck As Boolean
            selectCheck = DataView.CurrentRow.Cells(0).Value

    =========刪除部分======
            If (selectCheck = True) Then
                DataView.Rows.Remove(DataView.CurrentRow)
                MyData.DeleteCommand = xxxxxx

                MyData.Update(MDS)
                sBS.ResetBindings(True)
            End If

    xxxxxx這個部分不知該寫啥...

    2009年4月2日 下午 01:49
  • 風箏:
          
          你應該有個欄位是個Key吧,先假設這個Key的欄位名稱叫Key_no
          Dim command As OleDbCommand
          SQL字串就會變成"Delete 資料表名稱 Where Key_no=@Key_no" 
          你用Excel,我照抄一下
          所以 command = New OleDbCommand("Delete [sheet1$] Where Key_no=@Key_no",MyOleDb_cn )
          Dim parameter As OleDbParameter
          command.Parameters.Add("@Key_no", OleDbType.Integer, 4, "Key_no")    
                                                                   ============== 
                                                                   型別與長度 

          繼續加油



    2009年4月2日 下午 02:45
    版主
  • 我現在設定的是
    當CheckBox的值為True
    且該列為整列選取時
    才可以刪除

    若依大大您的說法
    那個...Key_no我可以寫成"DataView.CurrentRow"囉??

    來試試看先...

    2009年4月2日 下午 02:51
  • 不是啦..Key_no應該是一個欄位,而這個欄位中的值是不重覆的獨一值
    例如說客戶建檔,一般都會用其統一編號當為Key值,而此table中,不會有兩列的統一編號為相同
    否則你很難下命令去做Update或Delete的動作
    如果沒有Key值,在作update 或 delete不就得變成先將Table清空,然後把資料重新insert,這樣也太辛苦了吧

     
    2009年4月2日 下午 03:16
    版主
  • 喔...
    那麼若我是利用每列前方的CheckBox去當判斷
    則是將Key_no的值指定為CheckBox囉...
    2009年4月3日 上午 12:45
  • 當然不是,Key_no應該要存在於你的實際資料中
    CheckBox只存在於畫面,沒法當資料表的查詢條件
    來個小例子,你原始資料可能這樣呈現

    Key_no       St_Name
    1                 小叮噹
    2                 葉大雄
    3                 宜靜
    4                 技安
    5                 阿福
    然後你把這資料表load到畫面的DataGridView中<不過你把key_no隱藏了,用visible=false>
    變成<◎畫面打X表示為點選要刪除的東西>
    CheckBox     St_name
      X               小叮噹
      X               葉大雄
                       宜靜
                       技安
      X               阿福

    這個時候刪除指令就有一個依據是要刪除Key_no=1,2,5的資料...
    道理上差不多就是這樣
    2009年4月3日 上午 03:39
    版主
  • 若是這樣
    那麼我應該要利用每筆資料都有不同的...編號來做為刪除基準嚕...

    來試試看...
    2009年4月3日 上午 05:15
  • 目前將刪除功能的code改寫成如下:
            Dim selectCheck As Boolean
            Dim deleteCmd As OleDb.OleDbCommand
            Dim selectNumber As

            Dim paraMeter As OleDb.OleDbParameter
            selectCheck = DataView.CurrentRow.Cells(0).Value

            If (selectCheck = True) Then
                '======刪除DataGridView上顯示的資訊======
                DataView.Rows.Remove(DataView.CurrentRow)
                MyData.Update(MDS)
                sBS.ResetBindings(True)

                '======將資料庫的資訊同步刪除======
                deleteCmd = New OleDb.OleDbCommand("Delete [sheet1$] Where Key_no=@selectCheck", MyOleDb_cn)
                deleteCmd.Parameters.Add("@selectCheck", oledbtype.integer, 4, "Key_no")

            End If

    在第二段仍然不是很懂
    爬過許多文
    繼續爬文思考ing

    2009年4月3日 上午 06:16
  • 將code改寫成如下:

        Private Sub DeleteSong_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DeleteSong_Button.Click

            Dim selectCheck As Boolean
            Dim intRow As Integer
            Dim tempRow As DataRow

            selectCheck = DataView.CurrentRow.Cells(0).Value

            If (selectCheck = True) Then
                '======刪除DataGridview上顯示的資料列======
                intRow = DataView.CurrentCell.RowIndex
                MessageBox.Show(intRow)
                DataView.Rows.RemoveAt(intRow)
                sBS.ResetBindings(True)

                '======刪除後端資料庫的紀錄======
                MDS.Tables(0).Rows.RemoveAt(intRow)
            End If

        End Sub

    這樣就可刪除後端資料庫的紀錄了...

    現在剩下如把資料寫回Excel檔啦...
    加油加油......

    2009年4月3日 上午 06:48