2016-03-31 3 views
1

Я пытаюсь создать метод, используя элемент управления WebBrowser, перейти на веб-страницу и выполнить кастинг, пока страница не будет полностью загружена.Реактивные расширения, ожидающие события, не работают в первый раз около

К сожалению, зная, полностью ли загружена страница или нет, это не так просто и просто основано на событиях Navigating и DocumentCompleted.

Вместе они делают пару: когда Navigating пожаров, DocumentCompleted всегда будет стрелять после этого.

DocumentCompleted К сожалению, пожары для каждого кадра, который загружен, поэтому он может стрелять несколько раз на одной странице, а это означает, что это не редкость, чтобы увидеть следующую последовательность: Navigating - DocumentCompleted - Navigating - DocumentCompleted.

В результате я определил «полностью загруженную страницу» следующим образом: если DocumentCompleted уволил, а секунда истекла, а Navigating снова выстрелил в течение этого времени.

Во всяком случае, у меня есть следующий как мой код Rx, чтобы попытаться сделать выше:

_pageLoaded = navigating.Select(_ => documentCompleted.Delay(TimeSpan.FromSeconds(1))).Switch().FirstAsync(); 

Потом где-то я делаю await _pageLoaded, прежде чем продолжить.

Однако, по какой-то странной причине, это не работает в первый раз. Поэтому, когда приложение загружается, а WebBrowser перемещается где-то, он застревает на await _pageLoaded, пока оба Navigating и DocumentCompleted не зажгут огонь (т. Е. Я перейду к другому URL-адресу или тому же).

Я быстро проект просто проверить это и события Navigating и DocumentCompleted огонь, как и ожидалось, вот мой полный код:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private IObservable<object> _pageLoaded; 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     var navigating = Observable.FromEventPattern(webBrowser, "Navigating"); 
     var documentCompleted = Observable.FromEventPattern(webBrowser, "DocumentCompleted"); 
     _pageLoaded = navigating.Select(_ => documentCompleted.Delay(TimeSpan.FromSeconds(1))).Switch().FirstAsync(); 
    } 

    private async void button1_Click(object sender, EventArgs e) 
    { 
     webBrowser.Navigate(textBox1.Text); 
     await _pageLoaded; 
     MessageBox.Show("DoneLoading"); 
    } 

    private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
    { 
     MessageBox.Show("DocumentCompleted fired"); 
    } 

    private void webBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e) 
    { 
     MessageBox.Show("Navigating fired"); 
    } 
} 

В результате, когда кто-то вводит URL в TextBox (я тестировал с google.com) и попадает в Button является:

  • Навигационное выстрелил
  • DocumentCompleted выстрелил
  • ... ... ничего

Если затем на WebBrowser я нажимаю на ссылку, говорят изображения в верхней части, например, происходит следующее:

  • Навигационное выстрелил
  • DocumentCompleted выстрелил
  • 1 сек позже ... DoneLoading

Если я снова попал в Button что тогда случается:

  • Навигационное выстрелил
  • DocumentCompleted выстрелил
  • 1 сек позже ...DoneLoading
  • И, очевидно, если я еще не нажал ни одной ссылки на предыдущей странице, я получу вторую DoneLoading MessageBox.

Итак, мой вопрос прост: что это не работает в первый раз и как его исправить?

EDIT: Я просто сделал тест с другим сайтом, где события срабатывают многократно, и он отлично работает на этих сайтах. Таким образом, это буквально веб-сайты, где он срабатывает только один раз, и, похоже, это проблема только в первый раз.

ответ

4

Проблема заключается в том, что вы ожидаете после, которую вы назвали Navigate - так зависит от того, будет ли событие Navigate синхронно поднято или нет, либо Rx никогда не увидит первое событие навигации или это гонка.

Попробуйте это:

private async void button1_Click_1(object sender, EventArgs e) 
    { 
     var waiter = _pageLoaded.GetAwaiter(); 
     webBrowser.Navigate(textBox1.Text); 
     await waiter; 
     MessageBox.Show("DoneLoading"); 
    } 

Кстати, именно по этой причине его очень общий шаблон в асинхронном коде, чтобы начать ожидание события, чтобы закончить и затем инициировать его - так это хороший один для запомнить.

+1

Это была проблема. Это происходит из мышления Observables как событий и мышления, что «navigating = Observable.FromEventPattern (webBrowser,« Навигация »);« подписал меня на любое генерируемое им событие, что он просто поместит их в «поток», ожидающий все, что я хотел, когда захочу. Теперь я знаю лучше;) Спасибо! – JohnUbuntu

+0

Вы также можете найти этот ответ полезным: http://stackoverflow.com/questions/19895373/how-to-use-observable-fromevent-instead-of-fromeventpattern-and-avoid-string-lit/19896246#19896246 –

Смежные вопросы