很久沒用.net winform 做東西,對控件相對比較陌生,另外控件的UI也不是那么好改。公司項目需要有web客戶端,同時有軟件客戶端形式。考慮再三采用webBrowser+html 來實現 。用html 可以實現靈活的UI設計,js操作數據相應效果也不差。但是有以下幾個問題需要解決
一、兼容性
webBrowser 調用的是IE瀏覽器,一般的 在 xp操作系統之前 包括xp 用的是 兼容IE6的系統默認瀏覽器。 何為兼容IE6的默認瀏覽器呢。比如XP 賺的是IE7 那么我們知道每個IE版本里頭實際上是有兼容下一個版本的兼容視圖。那么這個時候webBrowser調用的瀏覽器是系統默認瀏覽器,如果系統是IE7調用的就是IE7,但是渲染的效果是兼容IE6的視圖,說白了就是IE6的渲染效果。 win7以上的系統 用的就是兼容IE7的系統默認瀏覽器(道理跟上述一樣)。
知道了調用的分別是什么用渲染效果的瀏覽器,那么我們要做的html 、js的兼容就只需要做到IE6、IE7這兩種瀏覽器兼容。事實上比起原始的winForm多了要做兼容的痛苦,而且有萬惡的IE6要做。
網上有些童鞋 為了避免兼容性的痛苦直接 用 WebKit .NET 項目,我也考慮到用WebKit .NET,但是通過以下兩個權衡放棄了
- 客戶端必須打包 WebKit .NET 到時客戶端變臃腫
- 項目同時又web端,web端做了IE的activex控件,activex直接調取控件不了
二、form窗體和js交互
Form 和 js交互是我要考慮的核心問題,起初我想到的是,在html端 通過ajax請求一個地址,地址里面帶一些參數。然后Form端通過webbrowser嗅探到地址的變化做出相應測處理:
<html> <head>echosong Test</head> <script type="text/javascript">//發送命令給Form function IframCmd (str) { document.getElementById("myFram").src=str; } </script> <body > <input type="button" value="發送頁面改版命令" onClick="IframCmd(‘發送字符’)"/> </body> </html>
using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using System.Diagnostics; namespace web { /// <summary> /// Description of MainForm. /// </summary> public partial class MainForm : Form { public MainForm() { InitializeComponent(); //加載本地的html文件 如果是服務器上直接跟絕對URL地址 this.webBrowser1.Navigate(System.Environment.CurrentDirectory+"/1.html"); } //監控地址變化,實現通宵方法(1 void WebBrowser1Navigating(object sender, WebBrowserNavigatingEventArgs e) { string cmdStr =e.Url.ToString();
if(cmdStr.Contains("__")){
MessageBox.Show(cmdStr);
} } } }
運行的效果當點擊發送命令的時候 Form會彈出發送字符
這種交互能達到目的,但是效率上有點問題,每次需要請求一個不必要的地址,反應速度讓人有點不爽。那么有么有js可以直接跟Form交互的辦法呢,我們知道用.net 寫的dll只要對外公開(注冊托管庫),那么js就能調用其的方法,那么webbowser Form具有這樣的特性沒有呢。趕緊實驗上代碼:
<html> <head><title>echosong Test</title></head> <script type="text/javascript"> //直接調用Form里頭的函數 function FormFun() { if (typeof window.external.getMaterialList != "undefined") { str = document.getElementById("inputTest").value; window.external.getMaterialList(str); } } function initialize () { //由於要等頁面加載完,Form才能給其賦值所以用這個函數來初始化告訴From頁面加載完畢讓From來初始化 inputTest數據 if (typeof window.external.inInt != "undefined") { window.external.inInt(); } } //發送命令給Form function IframCmd (str) { document.getElementById("myFram").src="http://www.baidu.com?="+str; } </script> <body onLoad="initialize()"> <input type="text" value="" id="inputTest" ><!--獲取Form數據--> <input type="button" value="直接調用FormFun函數" onClick="FormFun()"/> <input type="button" value="發送頁面改版命令" onClick="IframCmd('__發送字符')"/> <iframe src="" name="" id="myFram" width="1" height="1"></iframe> </body> </html>
/* * 由SharpDevelop創建。 * 用戶: song * 日期: 2013/10/4 * 時間: 22:50 * * 要改變這種模板請點擊 工具|選項|代碼編寫|編輯標准頭文件 */ using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using System.Diagnostics; namespace web { /// <summary> /// Description of MainForm. /// </summary> public partial class MainForm : Form { public MainForm() { InitializeComponent(); //加載本地的html文件 如果是服務器上直接跟絕對URL地址 this.webBrowser1.Navigate(System.Environment.CurrentDirectory+"/1.html"); //建立腳本通宵 this.webBrowser1.ObjectForScripting = this; } //用來直接被js調用的函數 public void getMaterialList(string str){ MessageBox.Show(str); } //在html文檔加載完全后用來給html原始賦值 public void inInt(){ this.webBrowser1.Document.GetElementById("inputTest").SetAttribute("value","頁面加載賦值給文本框"); } //監控地址變化,實現通宵方法(1 void WebBrowser1Navigating(object sender, WebBrowserNavigatingEventArgs e) { string cmdStr =e.Url.ToString(); if(cmdStr.Contains("__")){ MessageBox.Show(cmdStr); } } } }
然后在 C#項目的屬性文件
這里原本是false改成true。
這樣一來代碼正常跑通!!!
運行效果: 

這里 js 里面有個 window.external.***() 意思表示調用瀏覽器提供的外部方法。
