顯示具有 VB.NET 標籤的文章。 顯示所有文章
顯示具有 VB.NET 標籤的文章。 顯示所有文章

2012年3月12日 星期一

VS2003 DataGrid 去除空白行

最近在查怎麼控制 DataGrid 裡不要出現空白列
(不允許新增列)
查了 DataGrid 上上下下的屬性, 方法
都一無所獲
後來才發現要透過 Bind 的 DataTable 控制

只要加這一行就搞定 !
   dt.DefaultView.AllowNew = False

2012年3月11日 星期日

在 VS2003 的 DataGrid (WinForm) 中鑲入 ComboBox (下拉選單)

記錄一下 VS2003 的 DataGrid 中如何鑲入下拉選單
呈現出來的效果會是:
一開始 DataGrid 的欄位看起來是 DataGridTextBoxColumn (TextBox)
滑鼠點到該欄位時, 會自動變成下拉選單 (ComboBox)
當滑鼠點到其他欄位時, 欄位又會變回  DataGridTextBoxColumn
並將下拉選單中選定的文字顯示在 DataGridTextBoxColumn 上

Public Sub New()
   MyBase.New()
  
   InitializeComponent()

    ' 將 ComboBox 加入 DataGrid
   BindComboBox()
End Sub

Private Sub BindComboBox()
   Dim dt As New DataTable
   Dim conn As New SqlClient.SqlConnection("連線字串")
   Dim strSQL As String = "SQL敘述"
   Dim cmd As New SqlClient.SqlCommand(strSQL, conn)
   Dim adapter As New SqlClient.SqlDataAdapter(cmd)
   conn.Open()
   adapter.Fill(dt)
   conn.Close()

   ' 要鑲入 ComboBox 的欄位必須是 DataGridTextBoxColumn
   ' GridColumnStyles(n) : n 代表要在第幾個 DataGridTextBoxColumn 鑲入, 0,1,2,...
   Dim dgtbcCol As DataGridTextBoxColumn = DataGrid1.TableStyles(0).GridColumnStyles(2)
   Dim cbCol As New ComboBox
   ' 將 ComboBox 的寬度設得和 DataGridTextBoxColumn 一樣寬
   cbCol.width = 75
   ' 將 ComboBox onMouseOver 時的游標設為箭頭
   cbCol.Cursor = Cursors.Arrow
   ' 將 ComboBox 的樣式設為下拉選單
   cbCol.DropDownStyle = ComboBoxStyle.DropDownList

   ' 繫結 ComboBox 資料
   cbCol.DataSource = dt
   cbCol.ValueMember = "下拉值的欄位名稱"
   cbCol.DisplayMember = "下拉文字的欄位名稱"

   ' 增加下拉選單值改變時的 Event
   AddHandler cbCol.SelectionChangeCommited, AddressOf cbCol_SelectionChangeCommited
   ' 將 ComboBox 鑲入 DataGridTextBoxColumn 中
   dgtbcCol.TextBox.Controls.Add(cbCol)
End Sub

Private Sub cbCol_SelectionChangeCommited(ByVal sender As Object, ByVal e As EventArgs)
   ' 將 ComboBox 選定的文字顯示在 DataGridTextBoxColumn 上
   DataGrid1.Item(DataGrid1.CurrentCell) = Ctype(sender, ComboBox).Text
End Sub

要鑲入下拉選單的 DataGridTextBoxColumn 最好設為 ReadOnly
免得使用者不小心改掉欄位值

2012年2月13日 星期一

Excel 讀取 html 格式的儲存格換行效果

最近用 .NET 產生一個 html 格式的檔案
然後命名為 .xls , 偽裝成 Excel 檔案使用
結果發現在 <td> </td> 中使用 <br>
沒有達到預想中在儲存格換行的效果

幸好找到這一篇 :
[HTML][CSS] 使用 HTML <table> 匯出 Excel 時的斷行 (<br/>) 處理
(From : yilin 的程式日記)

<br style="mso-data-placement: same-cell;" >
只要加上 css , 就可以符合我的需求了
真是太感恩了~

2012年1月31日 星期二

迴圈搭配DataAdapter.Fill陷阱

今天在追蹤一個資料異常寫入的問題
發現原因出在迴圈搭配 DataAdapter.Fill 上

有問題的程式大致如下:
Dim dt As New DataTable
Dim saDept() As New String {"A01", "A02"}

For i As Integer = 0 To saDept.Length - 1
   Dim strSQL As String = "SELECT * FROM Employee WHERE Dept = '" & saDept(i) & "' "
   Dim scCmd As New SqlClient.SqlCommand
   Dim sdaAdapter As New SqlClient.SqlDataAdapter
   scCmd.CommandText = strSQL
   sdaAdapter.SelectCommand = scCmd
   sdaAdapter.Fill(dt)
   .
   .
   .
Next

之前一直以為 DataAdapter.Fill 執行時
會先清空 DataTable 內容再重新寫入資料

沒想到實際動作是
保留 DataTable 內的資料, 再將新資料 append 進 DataTable
導致這次資料異常寫入

只要在 DataTable 使用完後 (Next 上方)
加一個 dt.Clear()
就可解決這個問題
算是學到了一個經驗

2011年11月30日 星期三

使用 7-Zip 壓縮檔案

最近要壓縮 Email 附件檔
所以就挑了 7-Zip 來使用(免費)
這邊就記錄一下使用方式

   Dim p as new Diagnostics.Process()      
   ' 7z.exe 的路徑
   ' 也可以將 7z.exe 直接 Copy 到程式資料夾下
   p.StartInfo.Filename = "C:\Progra~1\7-Zip\7z.exe"
   ' a : 加入壓縮檔
   ' -tzip : 以 zip 方式壓縮
   ' -v3m : 每 3 MB 切割一個壓縮檔
   ' ZipFiles : 要壓縮的資料夾或檔案名稱 (可使用相對或絕對路徑)
   p.StartInfo.Arguments = "a -tzip -v3m ZipFiles"
   p.Start()
   p.WaitForExit()  ' 等待壓縮完成才進行之後的程式段

7-Zip 的相關參數設定可參考 [此處]

2011年3月22日 星期二

寫支自動通報 Windows Tasks 執行結果的程式

Server 上通常都掛載了一堆的 Windows Tasks
當每天要監控一堆 Server 的 Windows Tasks 就是件累人的事
透過 VB.NET 寫一支自動通報執行結果的程式
把各 Server 的 Windows Tasks 執行結果 Email 出來
應該會省點功...

首先利用 schtasks.exe 將 Windows Tasks 的執行狀況匯出為 csv
所以我寫了一隻 .bat 來做這件事
要注意的是, 我這邊實現的環境是 Windows Server 2003
Win7 的 schtasks.exe 匯出的格式和 Windows Server 2003 不太相同
如果要在 Winy 環境上實現, 可能要再花一些時間分析匯出的 csv

TasksToCSV.bat 的內容 :
   schtasks -query -fo csv -v > Tasks.csv

接下來就是 Coding Time 了
就僅針對產生 csv 及擷取內容的方法記錄
Imports System.IO
Imports System.Diagnostics
Imports System.Text

Private Sub GenerateTaskCSV()
   ' 清除舊的 CSV
   Dim fiCSV As New FileInfo(Directory.GetCurrentDirectory() & "\Tasks.csv")
   If fiCSV.Exists = True Then
      fiCSV.Delete()
   End If

   ' 將 Windows Tasks 匯入新的 CSV
   Dim p As Process = Process.Start("TasksToCSV.bat")
   ' 等待 .bat 執行結束
   p.WaitForExit()
End Sub

Private Function GetMailContent(ByVal FilePath As String) As StringBuilder
   Dim sbMailContent As New StringBuilder
   ' 設定要查詢的欄位
   Dim aryColumns() As String = {"主機名稱", "工作名稱", "狀態", "上次執行時間"}
   Dim intServerNamePos As Integer = 0
   Dim intStatusPos As Integer = 2
   Dim aryColPos(aryColumns.Length) As Integer
   Dim strLine As String = ""

   sbMailContent.AppendLine("<table>")
   sbMailContent.AppendLine(" <tr>")
   For t As Integer = 0 To aryColumns.Length - 1
      sbMailContent.AppendLine("<th>" & aryColumns(t) & "</th>")
   Next
   sbMailContent.AppendLine(" </tr>")

   Dim srReader As New StreamReader(FilePath, Encoding.Default)
   strLine = srReader.ReadLine()
   If Len(strLine) > 0 Then

      ' 找要查詢欄位的位置
      Dim aryHeader() As String = strLine.Split(""",""")
      For c As Integer = 0 To aryColumns.Length - 1
         For h As Integer = 0 To aryHeader.Length - 1
            If aryColumns(c) = Replace(aryHeader(h), """", "") Then
               aryColPos(c) = h
               h = aryHeader.Length
            End If
         Next
      Next

      strLine = srReader.ReadLine()
      While (Len(strLine) > 0)
         ' 如果抓出來的行資料最後不是雙引號結尾, 表示資料跨行
         ' 就繼續抓出下一行, 直到以雙引號結尾
         While (Right(strLine, 1) <> """")
            strLine = strLine & srReader.ReadLine()
         End While
         Dim aryContent() As String = strLine.Split(""",""")
         Dim strColumnValue As String = ""

         sbMailContent.AppendLine(" <tr>")
         For c As Integer = 0 To aryColumns.Length - 1
            If Len(ServerName) = 0 AndAlso c = intServerNamePos Then
               ServerName = Replace(aryContent(aryColPos(c)), """", "")
            End If
            strColumnValue = Replace(aryContent(aryColPos(c)), """", "")
            sbMailContent.AppendLine("<td>" & strColumnValue & "</td>")
         Next
         sbMailContent.AppendLine(" </tr>")
         strLine = srReader.ReadLine()
      End While

   End If
   sbMailContent.AppendLine("</table>")

   Return sbMailContent
End Function

2011年1月31日 星期一

VB.NET 產生 Excel 圖表另存圖片

記錄一下怎麼產生 Excel 圖表並另存成圖片

1.開啟一個空白 Excel, 將要填的資料格式都準備好, 並插入想要的圖表在裡面
2.將 Excel 儲存為 Template.xls 放入專案 \bin\debug\ 下
3.撰寫 VB.NET 程式段填寫資料 (圖表會隨資料異動而改變)

'開啟 Template Excel
Dim strTemplatePath As String = Directory.GetCurrentDirectory & "\Template.xls"
Dim xlsApp As New Application()
Dim xlsWorkBook As Workbook = xlsApp.Workbooks.Open(strTemplatePath)
Dim xlsWorkSheet As Worksheet = CType(xlsWorkBook.Worksheets("Sheet1"), Worksheet)

'填入 Excel 資料
..................................

'另存為 Html (產生圖表圖片)
Dim strHtmlName As String = Directory.GetCurrentDirectory & "\Chart.htm"
xlsWorkBook.SaveAs(strHtmlName, XlFileFormat.xlHtml)

'關閉 Excel
xlsWorkBook.Saved = True
xlsApp.Quit()
xlsApp = Nothing
GC.Collect()
GC.WaitForPendingFinalizers()

這樣 \bin\debug\ 下就會多了個 Chart.htm 檔案及 Chart.files 資料夾
Chart.files 資料夾下會有個 image001.gif 圖片
這就是我們要的圖片檔了
(p.s 如果 Template.xls 裡有多張圖表, 會依序命名為 image001, image002...)

2010年12月31日 星期五

.NET 網頁自動輸入及Submit form

記錄一下.net要怎麼連外部網頁並進行自動輸入與Submit form

先加入namespace
Imports System.Net

Dim wbBrowser As New WebBrowser()

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
   '加入瀏覽器正在轉址時的event
   AddHandler wbBrowser.Navigating, AddressOf wbBrowser_Navigating
   '加入瀏覽器轉址完成的event
   AddHandler wbBrowser.Navigated, AddressOf wbBrowser_Navigated
End Sub

Private Sub wbBrowser_Navigating(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserNavigatingEventArgs)
   '當網頁按鈕click flag為true,且發生轉址時
   If WebSubmit = True Then
      '設定瀏覽器轉址狀態flag
      WebNavigating = True
      '清除網頁按鈕click flag
      WebSubmit = False
   End If
End Sub

Private Sub wbBrowser_Navigated(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserNavigatedEventArgs)
   '當瀏覽轉址狀態flag為true,且已轉址完成時
   If WebNavigating = True Then
      '取得結果頁的內容
      GetResult()
      '清除瀏覽器轉址狀態
      WebNavigating = False
   End If
End Sub

'/***等待瀏覽器處理完成***/
Private Sub WaitForResponse()
   '如果Browser的狀態還未準備好,就繼續處理
   Do Until wbBrowser.ReadyState = WebBrowserReadyState.Complete
      Application.DoEvents()
   Loop
End Sub

'/***輸入網頁控制項的內容***/
Private Function InputControl(ByVal ControlName As String, ByVal ControlValue As String) As Boolean
   Try
      '取得網頁中的控制項並給其值
      '前提是控制項要有設Name屬性才能用此方式抓到
      '否則就要用wbBrowser.Document.getElementById method
      wbBrowser.Document.Body.All(ControlName).InnerText = ControlValue
      Return True
   Catch ex As Exception
      Return False
   End Try
End Function

'/***執行網頁按鈕的click動作***/
Private Function SubmitForm() As Boolean
   Try
      '因為目標網頁的Submit button沒有Name和ID屬性
      '所以只好用TagName來取得所有的Input物件
      '再判斷其type屬性是Submit的執行click動作
      Dim InputObjs As HtmlElementCollection = wbBrowser.Document.Body.GetElementsByTagName("input")

      For e As Integer = 0 To InputObjs.Count - 1
         Dim btnSubmit As HtmlElement = InputObjs(e)
         If btnSubmit.GetAttribute("type").ToString().ToUpper() = "SUBMIT" Then
            '設定網頁按鈕click flag
            WebSubmit = True
            btnSubmit.DomElement.click()
            e = InputObjs.Count
         End If
      Next
      Return True
   Catch ex As Exception
      Return False
   End Try
End Function

'/***取得網頁內容***/
Private Sub GetResult()
   Dim strWholeBody As String = wbBrowser.Document.Body.InnerHtml
   ...
End Sub

Private Sub btnCheck_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCheck.Click
   '連到目標網頁()
   wbBrowser.Navigate(tbUrl.Text)

   '等待網頁回應
   WaitForResponse()

   '將值填入目標控制項
   If InputControl("check", tbValue.Text) = True Then
      '送出 Form
      SubmitForm()
   End If
   '如果瀏覽器還在轉址狀態,就繼續讓瀏覽器處理
   While WebNavigating
      Application.DoEvents()
   End While
End Sub