引言
這兩天沉迷了Google SketchUp,剛剛玩夠,一時興起,研究了一下WebBrowser。
我在《WebBrowser控件使用技巧分享》一文中曾談到過“我現在可以通過WebBrowser實現對各種Html元素的操控,唯獨無法控制Html的上傳控件”,出于安全原因,IE沒有對上傳控件提供操控支持,這使得我們沒法像控制其他控件一樣用簡單的代碼進行賦值。
比較實際的解決方案就是模擬操作了,下面我就將演示通過鍵盤、鼠標兩種方式模擬點擊“瀏覽”按鈕,然后配合鍵盤模擬輸入文件路徑,并按回車鍵確認。
初始環境
測試使用了一個簡單的HTML頁面,頁中各個位置中分布了一些文件上傳控件,有些是直接放置的,有些是橫向排列的,有些是嵌套在表格中的,用以測試不同位置的觸發效果:
?
將此頁面用WebBrowser控件加載。
在程序界面中,我放置了一些控件用于選擇上傳文件所在目錄,測試時首先選定一個包含有文件的目錄,然后從中隨機抽選一個文件填寫到上傳控件中:
并在代碼中建立了一個輔助方法,用以讀取頁面上所有的文件上傳控件,在測試時也是從中隨機抽取一個進行操控:
List<HtmlElement> 讀取上傳控件()
{
??? var l = new List<HtmlElement>();
??? foreach (HtmlElement f in webBrowser1.Document.GetElementsByTagName("input"))
??? {
??????? if (f.GetAttribute("type") == "file")
??????? {
??????????? l.Add(f);
??????? }
??? }
??? return l;
}
在類中定義了一個Random類型成員變量用于生成隨機數:
Random R = new Random();
此外還定義了一系列方法,用于在點擊按鈕后,延遲3秒以等待文件瀏覽對話框打開,然后模擬輸入文件路徑,再模擬輸入回車鍵確定:
void 延遲操作對話框(string 填寫文件路徑)
{
??? button1.Enabled = button2.Enabled = button3.Enabled = false;
??? BackgroundWorker b = new BackgroundWorker();
??? b.RunWorkerCompleted += new RunWorkerCompletedEventHandler(b_RunWorkerCompleted);
??? b.DoWork += new DoWorkEventHandler(b_DoWork);
??? b.RunWorkerAsync(填寫文件路徑);
}
?
void b_DoWork(object sender, DoWorkEventArgs e)
{
??? Thread.Sleep(3000);
??? e.Result = e.Argument;
}
?
void b_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
??? SendKeys.Send(e.Result as string);
??? SendKeys.Send("{Enter}");
??? button1.Enabled = button2.Enabled = button3.Enabled = true;
}
這里就是通過使用BackgroundWorker組件在后臺延遲3秒,延遲結束后在回調事件中進行操作。
鍵盤模擬方式
先看錄制的動畫:
在這里首先選擇了一個上傳文件所在目錄,然后進行了幾次鍵盤模擬操作測試。
鍵盤模擬的操作流程如下:
首先激活WebBrowser控件
然后讓文件上傳控件獲取焦點,這時光標會處于文件上傳控件左側的文本框內
模擬輸入Tab鍵切換焦點到“瀏覽..”按鈕
模擬輸入空格鍵點擊該按鈕
然后就是延遲3秒等待文件選取對話框顯示,模擬輸入文件路徑并模擬輸入回車鍵即可
主要代碼如下:
private void button1_Click(object sender, EventArgs e)
{
??? var l = 讀取上傳控件();
??? var s = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
??? 鍵盤操作(l[R.Next(l.Count)], s[R.Next(s.Length)]);
}
?
void 鍵盤操作(HtmlElement 元素, string 填寫文件路徑)
{
??? webBrowser1.Select();
??? webBrowser1.Focus();
??? 元素.Focus();
??? SendKeys.Send("{Tab}");
??? SendKeys.Send(" ");
??? 延遲操作對話框(填寫文件路徑);
}
鼠標模擬方式
還是先看錄制的動畫:
鼠標模擬的主要流程是:
首先遞歸計算頁面中的文件上傳控件相對于頁面左上角的坐標位置
接著再遞歸計算WebBrowser控件相對于屏幕左上角的位置
在將位置值加上控件自身寬度及高度,并輔以修正值,以確保鼠標能夠點到按鈕上面
移動鼠標到計算好的位置處
單擊鼠標
然后也是延遲3秒等待文件選取對話框顯示,模擬輸入文件路徑并模擬輸入回車鍵
遞歸計算頁面元素相對于頁面坐上角位置的函數:
Point 計算坐標(HtmlElement 元素, Point 起始坐標)
{
??? var p = 起始坐標;
??? p.Offset(元素.OffsetRectangle.Location);
??? return 元素.OffsetParent == null ? p : 計算坐標(元素.OffsetParent, p);
}
遞歸計算控件相對于屏幕左上角位置的函數:
private Point 計算坐標(Control 控件, Point 起始坐標)
{
??? var p = 起始坐標;
??? p.Offset(控件.Location);
??? return 控件.Parent == null ? p : 計算坐標(控件.Parent, p);
}
此外,為了模擬鼠標移動和點擊,還需要引入Windows API:
[DllImport("User32")]
public extern static void SetCursorPos(int x, int y);
?
[DllImport("user32.dll")]
static extern void mouse_event(MouseEventFlag flags, int dx, int dy, uint data, int extraInfo);
?
[Flags]
enum MouseEventFlag : uint
{
??? Move = 0x0001,
??? LeftDown = 0x0002,
??? LeftUp = 0x0004,
??? RightDown = 0x0008,
??? RightUp = 0x0010,
??? MiddleDown = 0x0020,
??? MiddleUp = 0x0040,
??? XDown = 0x0080,
??? XUp = 0x0100,
??? Wheel = 0x0800,
??? VirtualDesk = 0x4000,
??? Absolute = 0x8000
}
主要代碼如下:
private void button2_Click(object sender, EventArgs e)
{
??? var l = 讀取上傳控件();
??? var s = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
??? 鼠標操作(l[R.Next(l.Count)], s[R.Next(s.Length)]);
}
?
void 鼠標操作(HtmlElement 元素, string 填寫文件路徑)
{
??? var p = 計算坐標(元素, new Point());
??? p = 計算坐標(webBrowser1, p);
??? p.Offset(元素.OffsetRectangle.Width - 5, 元素.OffsetRectangle.Height + 15);
??? SetCursorPos(p.X, p.Y);
??? mouse_event(MouseEventFlag.LeftDown | MouseEventFlag.LeftUp, 0, 0, 0, 0);
??? 延遲操作對話框(填寫文件路徑);
}
總結
兩種方法中推薦使用鍵盤模擬方法,簡單而直接;鼠標模擬方法需要使用到API,還需要精確計算,并且如果頁面帶有滾動條,且滾動條進行了滾動或文件上傳控件處于可視區之外的話,將無法通過上述方法計算和操控,而其優點僅僅是直觀一些而已。
?
下載本文的示例源代碼:http://www.uushare.com/user/icesee/file/1869210
下載本文的XPS版本:http://www.uushare.com/user/icesee/file/1869213