IMO, what you’re trying to do is indeed a legit scenario for UI testing automation. IIRC, in early versions of IE it was possible to populate the <input type="file"/>
field with a file name, without showing up the Choose File
dialog. For security reason, this is no longer possible, so you have to send keys to the dialog.
The problem here is that file.InvokeMember("Click")
shows a modal dialog, and you want the keys to be sent to that dialog, but SendKeys.Send
gets executed after the dialog has been closed (it’s modal, after-all). You need to let the dialog open first, then send the keys and let it close.
This problem can be solved using WinForms Timer
, but I’d prefer using async/await
and Task.Delay
for this (working code):
async Task PopulateInputFile(HtmlElement file)
{
file.Focus();
// delay the execution of SendKey to let the Choose File dialog show up
var sendKeyTask = Task.Delay(500).ContinueWith((_) =>
{
// this gets executed when the dialog is visible
SendKeys.Send("C:\\Images\\CCPhotoID.jpg" + "{ENTER}");
}, TaskScheduler.FromCurrentSynchronizationContext());
file.InvokeMember("Click"); // this shows up the dialog
await sendKeyTask;
// delay continuation to let the Choose File dialog hide
await Task.Delay(500);
}
async Task Populate()
{
var elements = webBrowser.Document.GetElementsByTagName("input");
foreach (HtmlElement file in elements)
{
if (file.GetAttribute("name") == "file")
{
file.Focus();
await PopulateInputFile(file);
}
}
}
IMO, this approach is very convenient for UI automation scripts. You can call Populate
like this, for example:
void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
this.webBrowser.DocumentCompleted -= webBrowser_DocumentCompleted;
Populate().ContinueWith((_) =>
{
MessageBox.Show("Form populated!");
}, TaskScheduler.FromCurrentSynchronizationContext());
}