C#-如何在一段时间内阻止方法返回?
我有一个win forms应用程序,它包含一个Web浏览器控件。由于导航的异步特性,我需要能够在web浏览器上添加操作之间的延迟 Document_Complete事件毫无价值,因为它没有考虑到一个页面可能包含多个AJAX请求。该事件经常发生多次 更新 AJAX请求是在加载页面时发出的。因此,页面加载和某些DIV中的内容是通过HTTP请求获取的。因此,当文档第一次加载,然后每个(AJAX)HTTP请求返回时,会引发Document_Complete事件。不,布埃诺 更新2 我的应用程序尝试从Webbrowser.Document对象读取HtmlElements。因为代码的执行速度比HTTP请求返回的速度快。。。文档对象不包含所有html元素 我需要的是某种方法来延迟主线程中方法的调用。我尝试过使用计时器:C#-如何在一段时间内阻止方法返回?,c#,asynchronous,timer,webbrowser-control,C#,Asynchronous,Timer,Webbrowser Control,我有一个win forms应用程序,它包含一个Web浏览器控件。由于导航的异步特性,我需要能够在web浏览器上添加操作之间的延迟 Document_Complete事件毫无价值,因为它没有考虑到一个页面可能包含多个AJAX请求。该事件经常发生多次 更新 AJAX请求是在加载页面时发出的。因此,页面加载和某些DIV中的内容是通过HTTP请求获取的。因此,当文档第一次加载,然后每个(AJAX)HTTP请求返回时,会引发Document_Complete事件。不,布埃诺 更新2 我的应用程序尝试从We
private void startTimer()
{
timer.Interval = 2000;
timer.Start();
while (!BrowserIsReady)
{
//Wait for timer
}
}
这将锁定线程,并且不会触发勾号事件。这种循环永远不会结束
我想运行一系列类似这样的方法:
Navagate("http://someurl.com");
//delay
ClickALink();
//delay
Navagate("Http://somewhere.com");
//delay
我能用定时器和后台工作人员解决这个问题吗?有人能提出一个可能的解决方案吗?不幸的是,您必须调用
Application.DoEvents()
,才能使浏览器正常工作。除此之外,我还关注ReadyState
属性
while (BusyNavigating || (wbBrowser.ReadyState != WebBrowserReadyState.Complete))
{
Application.DoEvents();
}
文档_Complete会告诉您页面何时完成加载
AJAX只是让它能够加载其他内容。某些Web应用程序(如StackOveflow)在计时器上有AJAX调用,这意味着您的应用程序永远不会完全加载,因为总会有一个AJAX调用等待进行/返回
这是一个问题,因为AJAX函数的回调可能会启动另一个AJAX函数。如果不解析它们的整个页面(创建一个执行树),就无法确定页面何时真正完全加载
也许您可以明确说明您的应用程序需要等待什么,直到所有AJAX调用完成,以及为什么等待文档完成还不够好 我认为您可能遇到的一个问题(因为代码不完整,所以无法判断)是,当需要调用时,您试图在控件上执行一些操作 我编写了一个小表单,每五秒钟更改一次url。请记住,在后台线程上询问web浏览器的状态也是不允许的
public partial class Form1 : Form
{
System.Timers.Timer t = new System.Timers.Timer();
Stack<string> urls = new Stack<string>();
public Form1()
{
InitializeComponent();
urls.Push("http://stackoverflow.com/");
urls.Push("http://msdn.microsoft.com/");
urls.Push("http://maps.google.com");
t.AutoReset = false;
t.Interval = 5000;
t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
}
void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (urls.Count > 0 )
{
string url = urls.Pop();
SetUrl(url);
}
t.Interval = 5000;
t.Start();
}
static void SynchronizedInvoke(ISynchronizeInvoke sync, Action action)
{
// If the invoke is not required, then invoke here and get out.
if (!sync.InvokeRequired)
{
// Execute action.
action();
// Get out.
return;
}
// Marshal to the required thread.
sync.Invoke(action, new object[] { });
}
private void SetUrl(string url)
{
SynchronizedInvoke(webBrowser1, () => webBrowser1.Navigate(url));
}
private void button1_Click(object sender, EventArgs e)
{
t.Interval = 1;
t.Start();
}
}
公共部分类表单1:表单
{
System.Timers.Timer t=新的System.Timers.Timer();
堆栈URL=新堆栈();
公共表格1()
{
初始化组件();
URL.Push(“http://stackoverflow.com/");
URL.Push(“http://msdn.microsoft.com/");
URL.Push(“http://maps.google.com");
t、 自动重置=错误;
t、 间隔=5000;
t、 已用+=新系统.计时器.延时器(t_已用);
}
无效时间(对象发送器,System.Timers.ElapsedEventArgs e)
{
如果(URL.Count>0)
{
字符串url=url.Pop();
SetUrl(url);
}
t、 间隔=5000;
t、 Start();
}
静态无效SynchronizedVoke(IsSynchronizeInvoke sync,Action Action)
{
//如果不需要调用,那么在这里调用并退出。
如果(!sync.invokererequired)
{
//执行操作。
动作();
//出去。
返回;
}
//封送到所需的线程。
调用(操作,新对象[]{});
}
私有void SetUrl(字符串url)
{
SynchronizedInvoke(webBrowser1,()=>webBrowser1.Navigate(url));
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
t、 间隔=1;
t、 Start();
}
}
谢谢你的建议。这就是我昨晚提出的“延迟”解决方案。感觉就像用蒸汽压路机碾碎花生,但我找不到更“优雅”的答案来解决这个问题
我正在剥离一个新的工作线程,该线程调用一个名为“AddDelay”的方法。此方法将使工作线程休眠一段时间。我的主(UI)线程在thread.IsAlive条件下循环,同时允许应用程序在线程未完成时接收操作系统消息
这似乎奏效了
private void Delay()
{
DelayTimer dt = new DelayTimer(1);
Thread thread = new Thread(new ThreadStart(dt.AddDelay));
thread.Start();
while (thread.IsAlive)
{
Application.DoEvents();
}
}
public class DelayTimer
{
private int _seconds;
public DelayTimer(int time)
{
_seconds = time;
}
public void AddDelay()
{
Thread.Sleep(_seconds*1000);
}
}
您可以考虑在线程名称空间中使用监视器类。下面的例子
using System;
using System.Threading;
namespace MonitorWait
{
class Program
{
private static readonly object somelock = new object();
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(SyncCall));
Thread.Sleep(5000); //Give the SyncCall a chance to run...
//Thread.Sleep(6000); //Uncomment to see it timeout.
lock (somelock)
{
Monitor.Pulse(somelock); //Tell the SyncCall it can wake up...
}
Thread.Sleep(1000); //Pause the main thread so the other thread
//prints before this one :)
Console.WriteLine("Press the any key...");
Console.ReadKey();
}
private static void SyncCall(object o)
{
lock (somelock)
{
Console.WriteLine("Waiting with a 10 second timeout...");
bool ret = Monitor.Wait(somelock, 10000);
if (ret)
{
Console.WriteLine("Pulsed...");
}
else
{
Console.WriteLine("Timed out...");
}
}
}
}
}
你不能简单地使用:
System.Threading.Thread.Sleep(1000);
这肯定也会有同样的效果?在等待http请求返回时,您在做什么,需要阻止执行?我这样问是因为设置计时器似乎不是一个好方法。如果页面加载速度很快,用户被迫长时间坐在那里怎么办。或者,如果页面速度非常慢,并且计时器认为它在应该加载之前就准备好了,那么我正在等待页面完成加载。为什么不收听
DocumentCompleted
事件呢?这似乎比阻塞主线程更可取。在AJAX的情况下,每个请求的这些状态都会更改多次。浏览器完成了所有HTTP请求后,如何实现暂停代码执行?@nick:是什么导致AJAX事件触发的?我在页面加载后或者在按钮上调用click方法时,使用这种技术睡觉都没有问题。如果AJAX事件是从计时器触发的,那么您将面临更大的挑战。您可能需要在循环中添加对页面元素的检查。很抱歉,web抓取是一项混乱的任务。Ajax请求由各种事件调用。我不控制网页设计。我感兴趣的是在页面加载后从页面中获取DOM元素。i、 e用户单击链接->ReadyState可能会在t之前更改4-5次