我一直在使用wait
和async
尝试许多不同的解决方案。似乎没有任何作用。我找不到真正完全等到页面已完全加载的解决方案。所有代码都在等待一段时间,但要等到页面加载完毕后才能进行下一个处理。
如何在页面上找到Document.GetElementById("quickFind_text_0")
元素之前将示例代码设置为等待模式?
这是我的代码:
private void button7_Click(object sender, EventArgs e)
{
webBrowser1.Navigate("https://company.crm4.dynamics.com/main.aspx?app=d365default&pagetype=entitylist&etn=opportunity");
webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("quickFind_text_0").SetAttribute("value", "Airbus");
webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("quickFind_text_0").InnerText = "Airbus";
//Thread.Sleep(2000);
HtmlElement fbLink = webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("mainContent").Document.GetElementById("quickFind_button_0"); ;
fbLink.InvokeMember("click");
}
P.S。我必须“两次”执行此操作,否则它将不起作用:
webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("quickFind_text_0").SetAttribute("value", "Airbus");
webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("quickFind_text_0").InnerText = "Airbus";
在VBA中,这有效:
While .Busy
DoEvents
Wend
While .ReadyState <> 4
DoEvents
Wend
是否可以在C#中执行相同的操作?
编辑:
我的完整代码如下。由于某种原因,异步/等待无法正常工作。
System.NullReferenceException HResult = 0x80004003消息=对象 引用未设置为对象的实例。来源= v.0.0.01
StackTrace:位于v._0._0._01.Browser.d__7.MoveNext() 在C:\ Users \ PC \ source \ repos \ v.0.0.01 \ v.0.0.01 \ Browser.cs:第69行
这是我的代码:
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace v.0._0._01
{
public static class WebBrowserExtensions
{
public static Task<Uri> DocumentCompletedAsync(this WebBrowser wb)
{
var tcs = new TaskCompletionSource<Uri>();
WebBrowserDocumentCompletedEventHandler handler = null;
handler = (_, e) =>
{
wb.DocumentCompleted -= handler;
tcs.TrySetResult(e.Url);
};
wb.DocumentCompleted += handler;
return tcs.Task;
}
}
public partial class Browser : Form
{
public Browser()
{
InitializeComponent();
}
private async void button7_Click(object sender, EventArgs e)
{
webBrowser1.Navigate("https://company.crm4.dynamics.com/main.aspx?app=d365default&pagetype=entitylist&etn=opportunity");
await webBrowser1.DocumentCompletedAsync(); // async magic
HtmlElement fbLink = webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("mainContent").Document.GetElementById("quickFind_button_0"); ;
fbLink.InvokeMember("click");
}
}
}
这是源代码:
现在我也注意到quickFind_text_0
和quickFind_button_0
总是以相同的词开头,但数字却像quickFind_text_1
和quickFind_button_1
或quickFind_text_2
和{{ 1}}。但是,通过手动单击,所有内容都适用于quickFind_button_2
和quickFind_text_0
。
答案 0 :(得分:2)
这是一种易于等待DocumentCompleted
事件的扩展方法:
public static class WebBrowserExtensions
{
public static Task<Uri> DocumentCompletedAsync(this WebBrowser wb)
{
var tcs = new TaskCompletionSource<Uri>();
WebBrowserDocumentCompletedEventHandler handler = null;
handler = (_, e) =>
{
wb.DocumentCompleted -= handler;
tcs.TrySetResult(e.Url);
};
wb.DocumentCompleted += handler;
return tcs.Task;
}
}
可以这样使用:
private async void button1_Click(object sender, EventArgs e)
{
webBrowser1.Navigate("https://company.crm4.dynamics.com/main.aspx");
await webBrowser1.DocumentCompletedAsync(); // async magic
HtmlElement fbLink = webBrowser1.Document.GetElementById("quickFind_button_0");
fbLink.InvokeMember("click");
}
await
之后的行将在页面加载完成后运行。
更新:这是等待特定元素显示在页面中的另一种扩展方法:
public static async Task<HtmlElement> WaitForElementAsync(this WebBrowser wb,
string elementId, int timeout = 30000, int interval = 500)
{
var stopwatch = Stopwatch.StartNew();
while (true)
{
try
{
var element = wb.Document.GetElementById(elementId);
if (element != null) return element;
}
catch { }
if (stopwatch.ElapsedMilliseconds > timeout) throw new TimeoutException();
await Task.Delay(interval);
}
}
例如,在调用使用XMLHttpRequest修改页面的click事件后,可以使用它:
someButton.InvokeMember("click");
var mainContentElement = await webBrowser1.WaitForElementAsync("mainContent", 5000);