当 Frame 控件导航到 HTML 内容时,Frame 控件在内部实例化本地WebBorwser ActiveX 控件。WPF 通过将功能控制应用于 WebBrowser ActiveX 控件来启用安全功能
因此,实际上,WPF中使用Frame来访问网页时,Frame内包含的东西并不是网页,而是WebBrowser,然后WebBrowser再访问网页,看起来,好像废话,理解这一点并不困难,WebBrowser依然是作为网页浏览的基本载体。
但是在编写代码时,理解这个道理非常重要,也非常容易疏忽。
在使用Frame访问或叫导航或叫装载Page对象时(Xaml),很直观,很容易理解,直接使用Frame的方法就可以完成一些操作,但是访问网页时,可能会出现意想不到的情况。
例如,使用Frame的Loaded或LoadCompleted方法时,会发现,网页还没加载完成这些事件就执行了。Loaded甚至是一开始就立刻执行了,LoadCompleted是在刚开始加载网页就执行的。
为什么会这样,似乎和Frame的这两个事件的描述不一样,但是在导航Page(Xaml)时就没问题。
详细阅读一下方法的说明和之前讲的Frame和WebBrowser的关系,其实可以找出答案。
还是以Loaded事件和LoadCompleted事件为例。
Loaded事件几乎在所有控件中都有,因此,Frame的Loaded方法和其他控件的Loaded是一样的,控件加载完成就触发。
LoadCompleted,这个对象是Frame内容加载完毕时触发的,看上去好像可以用这个方法来判断网页是否加载完毕,但是实际上依然不可以,为什么呢?如果Frame加载的是Page(Xaml),那么这个事件是管用的,但是,加载的是网页时,我们前面说过,Frame并没有直接加载网页,而是通过创建一个WebBrowser,然后这个WebBrowser再去加载网页,因此,Frame访问网页时,LoadCompleted是创建WebBrowser完成,而不是网页加载完成。
那么如何判断Frame中的网页是否加载完成呢?既然Frame并没自己加载网页,而是加载一个WebBrowser,然后由WebBrowser来加载网页,因此,我们要判断Frame中网页是否加载完成,其实依然是通过WebBrowser中的方法和事件来处理。这一点实际上又变回以前WinForm的操作方法了。
因此,我们在使用Frame来加载网页并与之互动时,需要记住,中间还有个WebBrowser,Frame只是创建一个WebBrowser,然后WebBrowser完成工作。Frame的Loaded只是自己完成时就触发,LoadCompleted事件是指WebBrowser实例化完成,网页加载完成是触发的WebBrowser的LoadCompleted。其他情况也遵循此原理。
还有一个地方要注意,在Frame触发LoadCompleted之前,Frame是还没有完成WebBrowser的创建的,因此,要想操作WebBrowser必须在LoadCompleted之后,否则会未实例化异常。
不要把WPF的Frame当做网页中的Frame来用了。