WebBrowser upload file - choose file dialog issue - c#

I have a win forms app and I'm opening a webBrowser inside the app. I have to use the browser, since I'm automating the actual browser UI flow of the site. I hit a snag trying to upload a file. The input element type is "file" and, as I've discovered, the only way to populate it programatically is to hit the browse button and select the actual file from the "Choose File to Upload" dialog.
I found useful answers on the topic like:
Uploading Files Not Working - Need Assistance
I tried using the above solution, but my code doesn't move beyond file.InvokeMember("Click");. So basically, once the "Choose File to Upload" dialog opens, the code pauses and waits for the dialog to close. I'm not sure how to proceed from here. Would really appreciate help on this and maybe a better suggestion on dealing with <input type="file"..." elements.

I hope the following answer will help you. Add timer control to your form.
Before you invoke the click event to the upload file dialog, start the timer.
timer1.Interval = 3000;
timer1.Start();
file.InvokeMember("Click");
In the timer tick event add the following coding
private void timer1_Tick(object sender, EventArgs e)
{
try
{
timer1.Stop();
SendKeys.SendWait("D:\\testing.txt"); // enter the file path, which suppose to upload.
SendKeys.SendWait("{TAB 2}");
SendKeys.SendWait("{ENTER}");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

Related

Click button after webBrowser1_DocumentCompleted event

I have a C# 4.0 WinForms application, which has a WebBrowser control and 2-buttons.
Clicking the first button sends a URL to the browser to navigate to a specified webSite.
Clicking the second button parses the OuterHtml of the webBrowser1.Document, looking for an "https://..." link for File Download.
The code then uses a webClient.DownloadFileAsync to pull down a file for further use in the application.
The above code successfully works, if I manually click those buttons.
In an effort to automate this for the end-user, I place the first button's click event, i.e. btnDisplayWeb.PerformClick(); in the form's Form1_Load event. This also works, allowing the webBrowser1 to populate its Document with the desired webSite.
However, I am unable to programatically click the 2nd button to acquire the web link for file download.
I have tried to place the 2nd buttons click event within the browser's DocumentCompleted event, as shown below.
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
btnMyUrl.PerformClick();
}
However, from what I've read on StackOverFlow and other sites, it's possible that this particular event gets called more than once, and hence it fails.
I've also attempted to loop for a number of seconds, or even use a Thread.Sleep(xxxx), but the browser window fails to populate until the sleep or timer stops.
I attempted to use the suggestions found on the following StackOverFlow site shown below.
How to use WebBrowser control DocumentCompleted event in C#?
private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
string url = e.Url.ToString();
if (!(url.StartsWith("http://") || url.StartsWith("https://")))
{
// in AJAX
}
if (e.Url.AbsolutePath != this.webBrowser.Url.AbsolutePath)
{
// IFRAME
}
else
{
// REAL DOCUMENT COMPLETE
}
}
However, in parsing the OuterHtml, nothing is returned in the first two sections, and in the third section, other elements are returned instead of the desired "https://..." link for File Download.
Interestingly, if I use a webBrowser1.ReadyState event, as shown below, and place a MessageBox inside DocumentCompleted, this seems to allow the browser document to complete, because after clicking the OK button, the parsing is successful.
if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
{
MessageBox.Show("waiting", "CHECKING");
btnMyUrl.PerformClick();
}
However, I then have the difficulty of finding a way to click the OK button of the MessageBox.
Is there another event that occurs after the DocumentCompleted event.
OR, can someone suggest how to programmatically close the MessageBox?
If this can be done in code, then I can perform the buttonClick() of the 2nd button in that section of code.
After finding that the addition of a MessageBox allows the webBrowser1.Document to complete, and using webBrowser1.ReadyState event within the webBrowser_DocumentCompleted event, all I needed to do, was to find a way to programmatically close the MessageBox.
Further searching on StackOverFlow revealed the following solution on the site below.
Close a MessageBox after several seconds
Implementing the AutoClosingMessageBox, and setting a time interval, closed the MessageBox and allowed my button click, i.e. btnMyUrl.PerformClick(); to successfully parse the OuterHtml and now the code works properly.
Hopefully, if someone else discovers that placing a MessageBox within the webBrowser_DocumentCompleted event allows the document to complete; the aforementioned AutoClosingMessageBox will assist them as well.

Revit API External Command freezing after WinForms Close() event

I am trying to create an external command for Revit that pops up a windows forms that has a single text box for the user to enter a description. After the user clicks Ok, the form closes but Revit gets stuck in a loading motion. It doesn't freeze, it just is constantly loading something. When I pause debugging, the code only made it to the line form.ShowDialog(). If I take out the showdialog and just run it without the form, it runs fine.
I'll post my relevant code snippets below. The form is in its own .cs, separate from the external command .cs but still under the same namespace.
Form click events code:
private void CancelForm(object sender, EventArgs e)
{
isReport = false;
this.DialogResult = DialogResult.Cancel;
Close();
}
private void SubmitForm(object sender, EventArgs e)
{
isReport = true;
reportDesc = descriptionBox.Text;
this.DialogResult = DialogResult.OK;
Close();
}
Execute command:
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
//Get application and document objects
UIApplication uiapp = commandData.Application;
Document doc = uiapp.ActiveUIDocument.Document;
ReportForm ticket = new ReportForm();
ticket.ShowDialog();
The code stops processing after showdialog. From what I could read on it, I thought it might have to do with focus on Revit after the form closing or the form not closing properly but couldn't figure out how to fix it.
Any help would be greatly appreciated!
Here is an old sample that creates a minimal Windows form on the fly, displays it as a modal form and closes successfully afterwards: The Schedule API and Access to Schedule Data. Maybe that will help. Maybe the debugger is interfering with the form closing somehow?
I ended up remaking the entire addin, made sure I was using Jeremy Tammik's Revit Addin Wizard to initiate it, and it started working. Not exactly sure what fixed it but guessing it was some error in the set up or such.

How to send CTRL+S to MS Word?

I am working on a program that auto saves a Microsoft Office document after specific time (loop).
On a click of a button it will activate timer and after a given time delay it should send CTRL+S to Word and save the document.
Here is my code:
private void button1_Click(object sender, EventArgs e)
{
startTimer.Enabled = true;
stratTimer.Start();
}
private void startTimer_Tick(object sender, EventArgs e)
{
SendKeys.SendWait("^{s}");
MessageBox.Show("doc auto saved");
}
The problem is that SendKeys.Send("^{s}"); does not work.
How can I accomplish that?
SendKeys.SendWait sends keystrokes to the currently active window, so the keystrokes can be received by other window, like browser (if you are viewing this answer while the automation exe is running in the background). It is not a wise idea to send key strokes to arbitrary window.
This can partially explain why your code does not work in some cases. And it has other issues.
Just as MickyD's comment, don't use this "SendKeys" solution for automation nowadays. For auto save, VSTO is the right way to go.
See How to: Programmatically save documents.

FolderBrowserDialog not showing up on second form

Ok, this is the main essence of what I am trying to achieve and the symptoms of what it is doing.
I have a main windows form. On this form the user can click on a button that will open up a new and seperate form. This form will have a button that is supposed to display a FolderBrowserDialog. Instead it simply locks up form2 and never displays anything.
Here is essentially the code I have dealing with the form etc.
This is in the first form that is loaded after i do some uninteresting things.
FORM1.cs
//do stuff
//In a button.click method I do the following
Application.Run(new Form2(myParameters1, 2, 3));
This is the second form that is called from the first form
FORM2.cs
//do more stuff with the parameters on load
//user clicks on a button
private void button1_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
fbd.RootFolder = Environment.SpecialFolder.Desktop;
fbd.Description = "This is the browser dialog box";
if(fbd.ShowDialog() == DialogResult.OK)
{
//do stuff
}
}
After I click on the button the dialog box does not show up and the form2 gets locked from doing anything.
I have also attempted changing the
fbd.ShowDialog()
To
fbd.ShowDialog(Form2.ActiveForm)
with the same results.
Any help would be appreciated! If you need more info let me know and I can try to provide all that I can.
EDIT
I forgot to mention (and actually completely forgot) That the method that opens up the second form is a seperate thread.
So the first form starts a thread, which opens the second form, which is supposed to open a dialog which it is not. Now i think it has to do with the threading..
I have figured out my issue. It ended up being that the thread from Form1 that was opening Form2 was not able to open DialogBoxes because it was seperate from the UI thread entirely.
I ended up working around using that thread and just eliminated it completely which solved my problem. The dialog box opened up just as I wanted.
Thank you all for the responses though! They did help me figure out a few other things I failed to do correctly.
I had similar problem. Main GUI thread was creating a backgroundworker thread to write to database but when background thread is failed used to show a custom control dialog to save exception file. THis custom dialog was shown correctly however Browse button on it to open folderBrowserDialog to save the exception file wouldn't show. My custom control would show "Not Responding" in its title bar.
What I did was instead of calling Custom Control directly I made it call on UI thread itself
like this.
void DBThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
this.Invoke(new CrossThreadExceptionHandler(CatchInterThreadException), e.Error);
}
}

How to hide loading animation when an open/save dialog is showm to the user?

I have an export button in my application.
When I click the button, it posts back to the server and generates an Excel file.
I want to show a loading gif during the process, but when the open/save dialog shows, I want to hide the gif.
The problem is that I use Response.End to display the file open/save dialog.
Does anyone knows how can I call a client side function after Response.End, or anyone has another solution how can I hide the gif and let the user work?
here is a piece of my code:
protected void Page_Load(object sender, EventArgs e)
{
//starts the loading gif animation.
btnExport.Attributes.Add("onclick", "setTimeout(\"UpdateImg();\",300);");
}
protected void btnExport_Click(object sender, EventArgs e)
{
//generates the file
Response.ContentType = "application/vnd.openxmlformats- officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=ExcelDemo.xlsx");
Response.BinaryWrite(pck.GetAsByteArray());
Response.Flush();
//Response.End();
HttpContext.Current.ApplicationInstance.CompleteRequest();
//HERE I WANT TO STOP THE ANIMATION AND GO BACK TO THE PAGE!
}
Thank you,
Inbal.
This way you can not do that.
When you start send your data to the file and open a save dialog, your web page have lost the control and you can not do anything any more, the data are all go to the file save.
What other and in my opinion better, options you have.
You can use a handler .ashx to create and send your file, and you give the link to your page with the parameters you need to make the file.

Categories