2011年11月23日 星期三

[dotnet]webbrowser 做為 UI log 的眉眉角角

一開始的動作

'WebBrowser1 一開始,可以設定 DocumentText 來顯示第一個畫面。
若是想用,WebBrowser1.Document.Write,
因為一開始,WebBrowser1.Document 是 nothing,所以此路不通。
網路上也滿多人提出,先 WebBrowser1.Navigate("about:blank"),
然後用迴圈加上 Application.DoEvents() 等待 'WebBrowser1.Document 長好,
再用 WebBrowser1.Document.Write。

最後我的決定是,準備好一個檔案直讀進來就好。
因為程式是 multithread,保險起見,還是用 while 等 Document 長好。
但我不確定是否真有用,因為一定要用 Application.DoEvents() 讓 WebBrowser 去做事,
當然這時有其他事情發生也沒辦法阻止。

    Sub initUILogComponet()
        WebBrowser1.Navigate("UI.html")
        WebBrowser1.IsWebBrowserContextMenuEnabled = False
        While (True)
            Application.DoEvents()
            If Not WebBrowser1.Document.Body Is Nothing Then
                Exit While
            End If
        End While
    End Sub

更新畫面

要更新 UI 畫面,基本要做的就是檢查 thread 是否回到 form。
這裡用 Document 物件新增新的 tr。
等待之後,取出 Document 的 html 元素的 OuterHtml 再寫進檔案。
接著Navigate。
清除舊資料的方式就是把最舊的那一個元素的 OuterHtml 取出,
把它從 html 元素的 OuterHtml 裡消掉,
再寫進檔案後Navigate。

    Sub UpdateUILog(ByVal inType As EQS_ScreenType, ByVal intxt As String)
        If Me.InvokeRequired Then
            Me.Invoke(New LogDele(AddressOf UpdateUILog), New Object() {inType, intxt})
        Else
            Try
                Dim tr As HtmlElement
                Dim td As HtmlElement
                tr = WebBrowser1.Document.CreateElement("tr")
                td = WebBrowser1.Document.CreateElement("td")
                td.InnerText = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
                tr.AppendChild(td)
                td = WebBrowser1.Document.CreateElement("td")
                td.InnerText = intxt
                tr.AppendChild(td)
                Select Case inType
                    Case ERROR
                        tr.SetAttribute("class", "error")
                    Case M_INFO
                        tr.SetAttribute("class", "info")
                    Case M_MES
                End Select
                WebBrowser1.Document.Body.FirstChild.FirstChild.FirstChild.InsertAdjacentElement(HtmlElementInsertionOrientation.AfterEnd, tr)
                While (True)
                    Application.DoEvents()
                    If Not WebBrowser1.Document.Body Is Nothing Then
                        Exit While
                    End If
                End While
                Dim n_html = "<!doctype html>" & WebBrowser1.Document.GetElementsByTagName("html").Item(0).OuterHtml
                Dim n_sw As System.IO.StreamWriter = System.IO.File.CreateText("UI.html")
                n_sw.Write(n_html)
                n_sw.Close()
                WebBrowser1.Navigate("UI.html")
                Dim v As Integer
                v = 5
                If WebBrowser1.Document.Body.FirstChild.FirstChild.Children.Count > v Then
                    Dim t As String = WebBrowser1.Document.Body.FirstChild.FirstChild.Children(v).OuterHtml
                    Dim new_html As String = WebBrowser1.Document.GetElementsByTagName("html").Item(0).OuterHtml
                    t = t.Replace(vbNewLine, "")
                    new_html = new_html.Replace(vbNewLine, "")
                    new_html = new_html.Replace(t, "")
                    new_html = "<!doctype html>" & new_html

                    Dim sw As System.IO.StreamWriter = System.IO.File.CreateText("UI.html")
                    sw.Write(new_html)
                    sw.Close()
                    WebBrowser1.Navigate("UI.html")
                End If
            Catch ex As Exception

            End Try
        End If
    End Sub

 

保證一定得到更新後內容的方式

在 DocumentCompleted 事件去拿一定可以。
要注意的是,當初設定 DocumentText 的話,更新的內容會在 DocumentText。
而使用 Document 物件操作的,更新的內容要從 Document 物件拿。

    Private Sub WebBrowser1_DocumentCompleted(ByVal sender As Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
        If firstContextSetComplete = False Then
            firstContextSetComplete = True
            'UpdateUILog(FACETEA.EQS_ScreenType.M_INFO, "StartUp")
        End If
        Dim control As Control = Me.ActiveControl
        WebBrowser1.Focus()
        control.Focus()
    End Sub

用jQuery清除舊資料

因為 WebBrowser 控制項沒辦法支援 addEventHandler,所以我的腦筋動到 setInterval。
這個方法可行,但是無法存檔。
而且考量到使用 class 控制外觀非得存檔再Navigate,在兩個因素考量下,
所以清舊資料的事只能交給主程式本身來做。

[dotnet]WebBrowser控制項對於 tr 的 border 顯示

在WebBrowser控制項裡,

tr { border-bottom: 1px solid #000000;}

不會顯示線。

在 ie9 的話,上面那行再加

table { border-collapse:collapse;}

就會顯示線。

有人提到

tr td{ border-bottom: 1px solid #000000; }

可以解決問題。但是兩個 td 之間可能會有斷線。

[dotnet]WebBrowser控制項不可用script偵測新增節點

經過研究及試驗,在 ie9 以下這行可以成功

document.addEventListener("DOMNodeInserted",function(){alert('change')});

但是在WebBrowser控制項就失敗。

[dotnet]WebBrowser控制項可吃 css 及 script

經過研究及實驗,可正常使用一般在 html 中加入 css 及 script 的標記,
也可以引用外部 css 檔案及 script 檔案。

用 WebBrowser.Document 新增新的 element,有幾個現象:

  1. 新的 element 並不會套上 class 的設定。
  2. 新的 element 會直接套用 style 的設定。

要解決第1點,可以先寫檔,再 navigate,就會套用設定。
所以一氣呵成的流程就是:

  1. WebBrowser.Document 新增新的 element
  2. 確定 WebBrowser1.Document.GetElementsByTagName("html").Item(0).OuterHtml 已經是新的內容
  3. 開檔寫檔
  4. navigate

[dotnet].NET Framework 還是有分 32 和 64

這個算是記憶刷新,並留下資料。

http://msdn.microsoft.com/zh-tw/windows/gg537087

[dotnet]讓WebBrowser預設右鍵menu不出現

因為打算使用 WebBrowser 這個控制項當做 UI 上顯示 log 的控制項,
這是一個快速筆記。

為了讓右鍵不顯示,只要一行code的設定:

WebBrowser1.IsWebBrowserContextMenuEnabled = False

http://evabow.blogspot.com/2011/07/webbrowsermenu.html

[dotnet]WebBrowser1.DocumentText

因為打算使用 WebBrowser 這個控制項當做 UI 上顯示 log 的控制項,
這是一個快速筆記。

http://msdn.microsoft.com/zh-tw/library/system.windows.forms.webbrowser.documenttext(v=vs.85).aspx 

即使已要求另一份文件,這個屬性仍會包含目前文件的文字。如果設定這個屬性的值,然後立即重新擷取這個值,則在 WebBrowser 控制項尚未有時間載入新內容時,所擷取到的值可能會與設定的值不同。您可以在 DocumentCompleted 事件處理常式中擷取新的值。

有人說,用doevents等一下可以

        While (True)
            Application.DoEvents()
            If Not WebBrowser1.Document.Body Is Nothing Then
                Exit While
            End If
        End While