轉帖|其它|編輯:郝浩|2011-04-08 15:08:23.000|閱讀 2828 次
概述:如何從WPF的WebBrowser控件中獲得WebResponse內容?為何WebBrowser控件的Navigated事件參數NavigationEventArgs的WebResponse屬性始終為null?
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
問:
如何從WPF的WebBrowser控件中獲得WebResponse內容?為何WebBrowser控件的Navigated事件參數NavigationEventArgs的WebResponse屬性始終為null?
我們在一個WPF的WebBrowser的Navigated事件中,嘗試去輸出NavigationEventArgs e的WebResponse屬性,他始終是null。比如,
XAML代碼:
<WebBrowser x:Name="browser"/>
C#代碼:
browser.Navigated += new NavigatedEventHandler(browser_Navigated);
browser.Navigate(new Uri("//www.microsoft.com"));
//省略...
void browser_Navigated(object sender, NavigationEventArgs e)
{
Console.WriteLine(e.WebResponse.Headers); //輸出null
}
[相關MSDN英文貼://social.msdn.microsoft.com/Forums/en-US/wpf/thread/856608db-48ba-4492-bff1-3721618ff3ae]
答:
一般都會認為從WebBrowser中獲得WebResponse內容,可以從Navigated事件的NavigationEventArgs參數中獲得。但是,事實是這個參數始終在返回null值,導致無法真正獲得返回的內容。
解決這個問題,首先想到的是去了解WebBrowser控件的基本組成。我們知道,IE的結構是如下:
而對于一個WebBrowser控件(無論是Winform的還是WPF的),都是和這個架構類似的,不同的只是最上層的UI封裝。控件來說,是沒有IExplore.exe的包裝的,所以一般控件就沒有IE的某些特性,但是從底層來說,他們都使用了ShDocVw.dll和MSHTML.dll,控件只是對下方組件的一次封裝。那么這個Navigated事件是從誰拋出的呢?答案是ShDocVw.dll,當然,面向不同的封裝,拋到上方會遇到不同的處理。Wnform中的WebBrowserNavigatedEventArgs中沒有封裝WebResponse信息,而從WPF的WebBrowser中,卻包含了這個屬性。
接下來,從表象很難找到原因了,這個時候就需要借助下工具,比如我使用了Reflector (從這里可以下載到試用版://reflector.red-gate.com/download.aspx?TreatAsUpdate=1)去反編譯了一些源代碼,嘗試去分析下為什么會一直返回null。通過工具分析,我們可以找到下面的一個調用列表:
在NavigationEventArgs類中的_webResponse成員實際就是我們要分析的對象,他僅由NavigationEventArgs的構造函數調用。而從他的構造函數的被調用列表中,我們發現了兩類方法,一類是被定義在MS.Internal.Controls.WebBrowserEvent中的,還有是定義在System.Windows.Navigation.NavigationService中的。當然,我們可以想到,第一類是所謂WebBrowser控件的內部組件類,這個類實際就是所謂架構中對于ShDocVw.dll的一次.Net封裝。所以這個類的方法就是WebBrowser在Navigated的時候調用的。點擊顯示MS.Internal.Controls.WebBrowserEvent.NavigateComplete2方法的邏輯代碼:
[SecurityTreatAsSafe, SecurityCritical]
public void NavigateComplete2(object pDisp, ref object url)
{
//省略…
NavigationEventArgs e = new NavigationEventArgs(uri, null, null, null, null, true);
this._parent.OnNavigated(e);
//省略…
}
可以看出,代碼中直接使用null值構造了NavigationEventArgs參數,然后觸發WebBrowser.Navigated事件。(當然,你也可以看DocumentComplete方法,在這個里面一樣的用了null去構造后觸發了WebBrowser.LoadCompleted事件)
到此可以解釋為什么WebResponse屬性總是返回null了。
等等,還沒有結束。那么怎么去獲得WebBrowser呢? 我們還省略沒有去看另外的幾個NavigationService的方法,比如System.Windows.Navigation.NavigationService.FireNavigated方法邏輯代碼:
private void FireNavigated(object navState)
{
object extraData = (navState is NavigateInfo) ? null : navState;
try
{
NavigationEventArgs e = new NavigationEventArgs
(this.CurrentSource, this.Content, extraData, this._webResponse,
this.INavigatorHost, this.IsNavigationInitiator);
//省略…
}
可以看出,NavigationService在他的事件中封裝了WebResponse信息。這樣的話,就有了解決方案——
使用NavigationService去Navigate頁面,并且在Navigated事件中獲得。但是WebBrowser本身沒有支持NavigationService,在WPF中只有NavigationWindow和Frame支持了NavigationService,所以我們只需要使用這兩者,這里我的代碼是用了Frame替代了WebBrowser,
XAML:
<Frame x:Name="frame"/>
C#代碼:
frame.Navigated += new NavigatedEventHandler(frame_Navigated);
frame.NavigationService.Navigate(new Uri("//www.microsoft.com"));
//省略...
void frame_Navigated(object sender, NavigationEventArgs e)
{
Console.WriteLine(e.WebResponse.Headers);
}
[備注:]在WebBrowser和Frame之間,我的第一感覺是,如果你需要一個瀏覽控件有依賴屬性來支持綁定等WPF特性的話,那么就選擇Frame吧,它包含你所需要的依賴屬性,而WebBrowser沒有。 不過我還會推薦下一個第三方的WPF瀏覽器控件://wpfchromium.codeplex.com/ 基于Google的Chromium項目的。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn