【问题标题】:WPF Method to wait for DocumentCompleted EventWPF 方法等待 DocumentCompleted 事件
【发布时间】:2011-09-07 03:57:24
【问题描述】:

我知道这有been asked before,但我认为these solutions 不灵活。 DocumentCompleted 事件应该用于确定加载何时完成,而不是作为执行工作的方法。如果您需要执行多个不同的任务,每个任务都必须导航多次,将逻辑放在DocumentCompleted 事件中会将其变成一个难以阅读和维护的杂乱开关/外壳路由器。

您需要一些可以在您的方法执行导航期间实际等待的东西,以便您可以在您已经使用的方法中继续您的任务。我的第一个虽然是实际的 Wait() 方法。

我认为这样的事情很接近:

void WaitForLoad()
    {
        isLoading = true;
        while (isLoading)
        {
            if (Application.Current == null) break;
            Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, (DispatcherOperationCallback)delegate(object unused) { return null; }, null);
        }
    }

并在DocumentCompleted 事件中将 Isloading 设置为 false。

您应该能够在任何会导致页面加载的操作之后调用此方法。它有效,它有一些问题。

1) 在页面加载之前,它会将应用程序的 CPU 使用率提高到 35%,即使没有发生其他任何事情。

2) 如果应用程序在运行时尝试关闭,则循环将继续运行并使应用程序保持打开状态而没有窗口,因此当应用程序为空时需要中断。

这个问题可以解决吗,还是我搞错了?

编辑:我尝试在下面实施 ManualResetEvent 解决方案,但它导致了其他几个问题,我不确定是否可以在不造成比上述情况更混乱的情况下解决这些问题。由于 WebBrowser 在 UI 上,锁定线程会停止整个应用程序。如果工作在后台线程上完成,它可以被锁定,但是访问 WebBrowser 变得非常困难。

【问题讨论】:

  • 所以您正在寻找一种在等待文档完成加载时阻塞线程的方法?
  • 我不熟悉应用于线程的“块”这个术语。这听起来像我想要的,但我不确定。在 Google 中搜索“阻止”没有帮助,因为阻止在代码中具有不同且更常见的含义。
  • 阻塞线程意味着它在被解除阻塞之前不再执行;又名,lock 语句将阻塞所有线程,并且一次只让一个线程通过临界区。谷歌线程阻塞。
  • 同步事件看起来很有希望,我会看看是否可以使用 ManualResetEvent 来完成这项工作。谢谢你的提示。

标签: c# wpf browser


【解决方案1】:

在您的情况下,听起来您希望在等待文档加载时阻止特定线程。在这种情况下,你会做这样的事情:

  protected ManualResetEvent _resetEvent = new ManualResetEvent(false);

  public void WaitingThread()
  {
      _resetEvent.WaitOne();

      // Do stuff after the web browser completes. 
  }

  public void LoadWebPage()
  {
      webBrowser.Navigate(new Uri(url));
      webBrowser.DocumentCompleted = (s, e) => { _resetEvent.Set(); };
  }

基本上,当文档完成时,您会发出事件信号,等待事件的任何线程解除阻塞并继续执行。

【讨论】:

  • 刚刚在 msdn 上找到 ManualResetEvent,这看起来像我所追求的。然而,由于有几种方法将进行导航,看起来实际上有一个 documentcompleted 事件可能会更好,而不是每次都用一个 Lamba 进行实例化。我错了吗?
  • 这一切都取决于你的逻辑是什么。
  • 我开始遇到这种方法的局限性。等待线程不能在浏览器上工作,因为浏览器存在于 UI 线程上。如果将其移至后台线程,则调用开始变得比原来的 switch/case 路由混乱。
  • 你不应该阻塞 UI 线程;您的文档完成代码应该进入文档完成事件并在 Ui 线程上调度事件,或者将您的代码放在单独的线程中,然后等待文档完成事件被引发。听起来您正在阻塞 UI 线程,这是您不应该做的事情。
  • 这就是我的观点。当我的代码不在 UI 线程上时,它无法访问在 ui 线程上的 webbrowser。然后你要么将逻辑分割成多个组,要么使用调用来访问所有内容;无论哪种方式,它都不干净。
【解决方案2】:

我注意到您使用Dispatcher.CurrentDispatcher.Invoke 这对于调用以某种方式从另一个线程更新 UI 的方法很有用。但是从提供的代码来看,我在其他线程中看不到任何代码,然后是 UI。所以

  1. 在另一个线程上运行该代码。

  2. 在您的应用程序的关闭事件中,您可以创建isLoading=false; 等等,如果调用的方法是一种长时间运行的东西,则插入

    if(!isLoading) 返回;

    //或以其他合适的方式中断执行

编辑:

在多线程中处理这个问题的更好方法是使用一些Synchonization object

【讨论】:

  • 这只是一种休眠的方法,不会导致 UI 线程锁定。我希望应用程序的其余部分在页面加载时保持可用。
猜你喜欢
  • 1970-01-01
  • 2015-11-30
  • 2017-03-13
  • 2012-10-16
  • 2011-08-20
  • 2017-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多