问题
Our target is: Watin-enabled browser testing embedded in a .net winform.
Currently, we are using a .net WebBrowser control to embed browser behavior in a winform. We are attaching WatiN to the WebBroswer control on the form with code like this ( thanks prostynick ):
var thread = new Thread(() =>
{
Settings.AutoStartDialogWatcher = false;
var ie = new IE(webBrowser1.ActiveXInstance);
ie.GoTo("http://www.google.com");
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
The problem is this - the "winform browser" needs to handle popups during testing/automation.
Question: How can popups be handled when Watin is attached to a winforms webBrowser control ( and not using its own WatiN-generated IE window )?
a) Can Watin's DialogWatcher still be used? If so ...how?
b) If not, then perhaps we can write our own DialogWatcher -- but we would need an hWnd or processID to add it. Where would we get correct hWnd or processId in this scenario where Waitin does not have its own window or process?
Thanks in advance for any ideas ...alternate approaches that reach the same target are welcome!
回答1:
I have just upgraded to newest version of WatiN (head revision - 1166 - in trunk: https://watin.svn.sourceforge.net/svnroot/watin/trunk/src/). Since there was a change in original DialogWatcher
class it is now possible to use existing DialogWatcher
with fewer code.
Create class:
public class WebBrowserIE : IE
{
private IntPtr hwnd;
public WebBrowserIE(WebBrowser webBrowserControl)
: base(webBrowserControl.ActiveXInstance, false)
{
hwnd = webBrowserControl.FindForm().Handle;
StartDialogWatcher();
}
public override IntPtr hWnd
{
get
{
return hwnd;
}
}
protected override void Dispose(bool disposing)
{
hwnd = IntPtr.Zero;
base.Dispose(disposing);
}
}
Use it instead of original IE
class and see disappearing javascript alert dialog:
var ie = new WebBrowserIE(webBrowser1);
var thread = new Thread(() =>
{
ie.GoTo("http://www.plus2net.com/javascript_tutorial/window-alert.php");
ie.Button(Find.ByValue("Click here to display alert message")).Click();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Warning: Create WebBrowserIE
instance outside the thread. Otherwise you will have to modify this class to avoid cross-thread operation when reading Handle
property of Form
.
回答2:
Oh man, this question comes up so many times and I always writing something like: But with a little bit of hacking you can create your own based on original DialogWatcher class (from: How to use watin with WebBrowser control?), so I dug in my source code to find it and I will just show how I did it. Maybe it's not perfect, but it works and I didn't have any problems with it.
- Create
FormDialogWatcher
class by copying originalDialogWatcher
, changing class name, namespace etc. I have deleted following fields and methods from original class. This is probably not needed, but you will probably use only one instance of
WebBrowser
controll, so you don't really need this code and I am not sure if it will work properly after the changes without deleting this. To delete:private static IList<DialogWatcher> dialogWatchers
public static DialogWatcher GetDialogWatcher(IntPtr mainWindowHwnd)
public static DialogWatcher GetDialogWatcherFromCache(IntPtr mainWindowHwnd)
public static void CleanupDialogWatcherCache()
public void IncreaseReferenceCount()
public void DecreaseReferenceCount()
public int ReferenceCount { get; private set; }
private bool IsWindowOfIexploreProcess(Window window)
In
Start()
method replace this:if (new Window(MainWindowHwnd).Exists()) { var winEnumerator = new WindowsEnumerator(); var windows = winEnumerator.GetWindows(win => true);
with this:
var mainWindow = new Window(MainWindowHwnd); if (mainWindow.Exists()) { var winEnumerator = new WindowsEnumerator(); var windows = winEnumerator.GetWindows(window => window.ProcessID == mainWindow.ProcessID);
(the only real difference is inside
GetWindows
call)In
HandleWindow(Window window)
remove this line:if (!IsWindowOfIexploreProcess(window)) return;
That's all! To start it, just create it: new FormDialogWatcher(Handle)
where Handle
is just a property of Form
. You can probably create it after creating IE
object in your example code (LOL, I've just figured out, that there is my nick name in question :)) - Form_Load
or something like that. It will start immediately (see constructor) and the main loop will break after the window cease to exist.
EDIT: Be aware that if you set this class (or WatiN settings) to close unhandled dialogs, then even your MessageBox.Show
will be closed :)
EDIT 2 (important!): Whole explanation above is related to original DialogWatcher
class taken from WatiN SVN trunk revision 1056. Direct link to this revision and file: http://watin.svn.sourceforge.net/viewvc/watin/trunk/src/Core/DialogHandlers/DialogWatcher.cs?revision=1056&content-type=text/plain&pathrev=1056
来源:https://stackoverflow.com/questions/4455607/watin-and-net-winforms-webbrowser-control-is-dialogwatcher-possible