C#-如何在一段时间内阻止方法返回?

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

我有一个win forms应用程序,它包含一个Web浏览器控件。由于导航的异步特性,我需要能够在web浏览器上添加操作之间的延迟

Document_Complete事件毫无价值,因为它没有考虑到一个页面可能包含多个AJAX请求。该事件经常发生多次

更新

AJAX请求是在加载页面时发出的。因此,页面加载和某些DIV中的内容是通过HTTP请求获取的。因此,当文档第一次加载,然后每个(AJAX)HTTP请求返回时,会引发Document_Complete事件。不,布埃诺

更新2

我的应用程序尝试从Webbrowser.Document对象读取HtmlElements。因为代码的执行速度比HTTP请求返回的速度快。。。文档对象不包含所有html元素

我需要的是某种方法来延迟主线程中方法的调用。我尝试过使用计时器:

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次