Как я могу заблокировать возврат метода на некоторый интервал времени? - PullRequest
4 голосов
/ 24 августа 2010

У меня есть приложение win forms, которое содержит элемент управления веб-браузера. Мне нужно иметь возможность добавить задержку между операциями в веб-браузере из-за асинхронного характера навигации.

Событие Document_Complete бесполезно, так как оно не учитывает, что страница может содержать несколько запросов AJAX. Случай пожара много раз.

UPDATE

AJAX-запросы выполняются при загрузке страницы. Таким образом, страница загружается, и содержимое в некотором DIV выбирается через HTTP-запрос. Таким образом, событие Document_Complete возникает при первой загрузке документа, а затем, когда возвращается каждый (AJAX) HTTP-запрос. Нет Буэно.

UPDATE2

Мое приложение пытается прочитать HtmlElements из объекта Webbrowser.Document. Поскольку код выполняется быстрее, чем возвращаются запросы 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

Можно ли решить эту проблему с помощью таймера и BackgroundWorker? Может кто-нибудь предложить возможное решение?

Ответы [ 6 ]

1 голос
/ 26 августа 2010

Вы можете рассмотреть возможность использования класса Monitor в пространстве имен Threading.Пример ниже.

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...");
                }
            }
        }
    }
}
0 голосов
/ 26 августа 2010

Разве вы не можете просто использовать:

   System.Threading.Thread.Sleep(1000);

Это наверняка должно иметь тот же эффект?

0 голосов
/ 24 августа 2010

Спасибо за все предложения. Это решение «Задержка», которое я придумал прошлой ночью. Такое ощущение, что с помощью парового ролика можно расколоть арахис, но я не смог найти более «элегантного» решения этой конкретной проблемы.

Я раскручиваю новый рабочий поток, который вызывает метод с именем «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);
        }
    }
0 голосов
/ 24 августа 2010

Я думаю, что одна из проблем, с которыми вы можете столкнуться (не могу сказать, потому что код не завершен), заключается в том, что вы пытаетесь делать что-то под своим контролем, когда требуется вызов.

Я закодировал небольшую форму, которая меняет URL каждые пять секунд.Помните, что опрос состояния веб-браузера в фоновом потоке также не разрешен.

  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();
    }




}
0 голосов
/ 24 августа 2010

Document_Complete сообщает , когда страница закончила загрузку.

AJAX просто позволяет ему загружать что-то еще. Некоторые веб-приложения (например, StackOveflow) имеют вызовы AJAX по таймеру, что означает, что ваше приложение никогда не загрузится полностью, поскольку существует всегда вызов AJAX, ожидающий выполнения / возврата.

Это проблема, потому что обратный вызов для функции AJAX может просто запустить другую функцию AJAX. Без анализа всей их страницы (создания дерева выполнения) у вас действительно не будет способа определить, действительно ли страница полностью загружена.

Возможно, вы могли бы четко уточнить, что именно ваше приложение выполняет , которое должно ждать, пока все вызовы AJAX не завершатся, и почему ожидание Document_Complete не достаточно хорошо.

0 голосов
/ 24 августа 2010

К сожалению, вы должны позвонить Application.DoEvents(), чтобы браузер работал.Помимо этого, я также обращаю внимание на свойство ReadyState.

  while (BusyNavigating || (wbBrowser.ReadyState != WebBrowserReadyState.Complete))
  {
    Application.DoEvents();
  } 
...