InvokeMember ("отправить") на форме не перенаправляет браузер
Я использую элемент управления WebBrowser для проверки отправки формы, в данном конкретном случае действие является действием MVC, которое перенаправляет на другую страницу результатов.
Код действительно прост...
void _browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var parentForm = _my_find_form_function();
parentForm.SetAttribute("action", "http://localhost/tests/TestSubmission");
parentForm.InvokeMember("submit");
}
После отправки (которая работает, как ожидалось) я бы подумал, что следующее событие documentcompleted будет запущено после загрузки перенаправленной страницы. вместо этого загружается та же страница (с формой).
Есть ли что-то, что я упускаю?Спасибо
1 ответ:
Ладно, извините за задержку, я перешел к другому вопросу...
В любом случае, это действительно грубо, но вы должны быть в состоянии выбрать биты, которые вам нужны.
Исходная идея была изNoseratio , найденногоздесь .
Метод raisedynamicevent, работает аналогичным образом для асинхронных навигация, мониторинг состояния документа после события. когда ОК снова, возвращается. надо бы разобраться с делами "Аякса". нуждается в повторном факторинге немного и, возможно, много неправильно с ним, но, надеюсь, поможет кто-то.
/// the _profileQueue was a queue of URLs i wanted to nav through and find an /// form elem and "click" the submit button on private async void Next() { Submission res = null; if (_profileQueue.TryDequeue(out res)) { // dirty, but hold the details of the url i'm navigating to in the Tag _browser.Tag = res; var cts = new CancellationTokenSource(Properties.Settings.Default.BrowserNavigationTimeout); // cancel in 10s var html = await LoadDynamicPage(res.SiteProfile.URL, cts.Token); // this parses the dom once loaded (awaits for the page) ProcessSiteProfile(); Next(); } } // navigate and download async Task<string> LoadDynamicPage(string url, CancellationToken token) { // navigate and await DocumentCompleted var tcs = new TaskCompletionSource<bool>(); WebBrowserDocumentCompletedEventHandler handler = (s, arg) => tcs.TrySetResult(true); // i'm keeping the tcs in a concurrentdictionary against the browser object // again, this is pretty dirty but obviously felt like i needed it. _browserTasks[_browser] = tcs; using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true)) { // nav to page async this._browser.DocumentCompleted += handler; try { if (!string.IsNullOrWhiteSpace(url)) { this._browser.Navigate(url); await tcs.Task; // wait for DocumentCompleted } } finally { this._browser.DocumentCompleted -= handler; } } // get the root element var documentElement = this._browser.Document.GetElementsByTagName("html")[0]; // poll the current HTML for changes asynchronosly var html = documentElement.OuterHtml; while (true) { // wait asynchronously, this will throw if cancellation requested await Task.Delay(Properties.Settings.Default.BrowserNavigationWait, token); // continue polling if the WebBrowser is still busy if (this._browser.IsBusy) continue; var htmlNow = documentElement.OuterHtml; if (html == htmlNow) break; // no changes detected, end the poll loop html = htmlNow; } // consider the page fully rendered token.ThrowIfCancellationRequested(); // remove from task dictionary _browserTasks[this._browser] = null; return html; } async void ProcessSiteProfile() { // now process submission HtmlElement parentForm = null; ///////////////// // parse dom to find the form you're looking for // couple of helpers below /////////////////////// parentForm = HtmlElementQuery(_browser.Document, "myTextFieldInput"); var sub = (_browser.Tag as Submission); HtmlDocument doc = _browser.Document; if (parentForm != null) { var elements = parentForm.GetElementsByTagName("input"); foreach (HtmlElement el in elements) { // If there's more than one button, you can check the // element.InnerHTML to see if it's the one you want if (el.GetAttribute("type").ToLower() == "submit") { var cts = new CancellationTokenSource(Properties.Settings.Default.BrowserNavigationTimeout); // cancel in 10s var html = await RaiseDynamicEvent(el, "click", cts.Token); } } } } // used to raise an event with a dom element that would cause the document to change async Task<string> RaiseDynamicEvent(HtmlElement element, string evt, CancellationToken token) { // navigate and await DocumentCompleted var tcs = new TaskCompletionSource<bool>(); WebBrowserDocumentCompletedEventHandler handler = (s, arg) => tcs.TrySetResult(true); _browserTasks[_browser] = tcs; using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true)) { this._browser.DocumentCompleted += handler; try { element.InvokeMember(evt); try { await tcs.Task; // wait for DocumentCompleted } catch (TaskCanceledException) { // no the end of the world } } finally { this._browser.DocumentCompleted -= handler; } } // get the root element var documentElement = this._browser.Document.GetElementsByTagName("html")[0]; // poll the current HTML for changes asynchronosly var html = documentElement.OuterHtml; while (true) { // wait asynchronously, this will throw if cancellation requested await Task.Delay(500, token); // continue polling if the WebBrowser is still busy if (this._browser.IsBusy) continue; var htmlNow = documentElement.OuterHtml; if (html == htmlNow) break; // no changes detected, end the poll loop html = htmlNow; } // consider the page fully rendered token.ThrowIfCancellationRequested(); // remove from task dictionary _browserTasks[this._browser] = null; return html; } // couple of useful helpers HtmlElement FindParentByElement(string elementName, HtmlElement element) { if (element.Parent != null) { if (element.Parent.TagName.ToLower() == elementName.ToLower()) { return element.Parent; } else { return FindParentByElement(elementName, element.Parent); } } else { return null; } } HtmlElement HtmlElementQuery(HtmlDocument container, string query) { HtmlElement el = null; if (query.StartsWith("#")) { el = container.GetElementById(query.TrimStart('#')); } else { el = container.All[query]; } return el; }