尋找WindowsFormsHost的苦難歷程
好文一定要頂?。?!
原文鏈接
在WPF中使用傳統的WinForm控件時,需要用一個叫WindowsFormsHost的WPF控件將WinForm控件包裹起來,以實現WPF控件和WinForm控件的混合使用。如下:
void currentBrowser_Navigated(object sender, swf.WebBrowserNavigatedEventArgs e){ swf.WebBrowser currentBrowser = sender as swf.WebBrowser; swf.Control host = currentBrowser.Parent; DockPanel dockPanel = host.Parent as DockPanel; //some other work}執行程序,結果:"host.Parent as DockPanel"報錯:不能將WinForm控件轉換為WPF的DockPanel控件!
斷點調試,結果:發現host.Parent屬性是一個WinFormsAdapter的類型,不是WindowsFormsHost。
修改代碼:WinFormsAdapter adapter = host.Parent as WinFormsAdapter;結果:繼續報錯:系統無法識別WinFormsAdapter。
引入名字空間:using System.Windows.Forms.Integration;結果:還是報錯,系統依然無法識別。
到此,整個人的情緒是這個樣子的:



尋找WindowsFormsHost的困難之旅于是開始了!
google一次:"how to get the parent control WindowsFormsHost",結果:有討論,沒答案?。ㄔ谶@里消耗了大把大把的time)
google二次:"WinFormsAdapter",結果:它是一個internal class。怪不得無法識別?。ㄎ④洖槭裁匆@么做呢?希望有高手能分析分析)
ildasm:截圖如下:

發現:構造函數.ctor:void(class System.Windows.Forms.Integration.WindowsFormsHost)的參數想必就是我們的WindowsFormsHost,而從類型和命名上判斷,變量_host在構造函數中存儲了這個數據。
到此終于可以放松些了,雖然問題解決了,但始終還是很疑惑,為什么這個WinFormsAdapter要設計成internal,而且通過ildasm還發現_host作為私有變量也沒有屬性(PRoperty)封裝。微軟在WindowsFormsHost中設計了Child屬性以便向下尋找WinForm,那應該會考慮到人家WinForm向上尋找WPF啊,這樣internal一下,再private一下,是何用意?
WinFormsAdapter有什么不可告人的秘密,不便公開?我想沒必要!
或者微軟提供了其他的更好的辦法,不建議使用WinFormsAdapter,所以藏起來?見鬼,對樹(包括WPF的邏輯樹)的操作習慣就是這樣的,是長期以來形成的,別的辦法哪怕更好,這個因素你也得考慮一下啊,還可不是一個人的問題。
希望能有達人出現,分析分析這個問題,或者提出更好的辦法!
最后把反射部分的代碼附上:
swf.WebBrowser currentBrowser = sender as swf.WebBrowser; swf.Control adapter = currentBrowser.Parent; Assembly asm = typeof(WindowsFormsHost).Assembly; Type type = asm.GetType("System.Windows.Forms.Integration.WinFormsAdapter"); object parent = type.InvokeMember("_host", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance, null, adapter, new Object[] { }); WindowsFormsHost host = parent as WindowsFormsHost; DockPanel dockPanel = host.Parent as DockPanel;好文一定要頂!??!附上評論:
#1樓
沒看懂,看了我還是菜~悶~支持(0)反對(0)2009-11-25 15:07 | 咖啡色 #2樓
搞支持(0)反對(0)2009-11-25 15:20 | zhh007's Bolg #3樓
通過WinForm尋找WindowsFormsHost,是沒什么好方法。不過這樣也沒什么意義吧。WebBrowser對應WinForm的Control,而WindowsFormsHost對應WPF的FrameworkElement。從WPF來看,它的邏輯樹到WindowsFormsHost就到頭了。從WinFrom來看,WebBrowser需要他的Parent也是個WinForm的Control。WindowsFormsHost不能身兼二職,所以引入了一個WinFormsAdapter,一個Adapter,繼承自WinForm的Control。中間interOperation的事情就由他們兩個搞了。主要干活的是WindowsFormsHost,它需要把調用API-SetParent,設置Window和WinFormsAdapter的從屬關系,并且經過其他Interop類的幫助注冊ComponentDispatcher.ThreadFilterMessage,把WPF中的消息轉到WinForm體系來,使WebControl正常工作。至于為什么WinFormsAdapter是internal的,呵呵,它只用在WindowsFormsHost內部,藏起來,沒必要show吧。支持(0)反對(0)2009-11-25 16:26 | 周永恒 #4樓
這段解釋就足夠了,下面的反而說的有點牽強,多了未必就能解釋清楚。呵呵。其實lz不需要這么麻煩,比較合理的做法是跳過WebBrowser,使用WindowsFormsHost來參與處理邏輯。| 12345 | <DockPanel> <my:WindowsFormsHost Name="wfh"> <swf:WebBrowser Name="vvv" Tag="{Binding ElementName=wfh}"></swf:WebBrowser> </my:WindowsFormsHost></DockPanel> |
| 1234567891011 | void currentBrowser_Navigated(object sender, swf.WebBrowserNavigatedEventArgs e){ swf.WebBrowser currentBrowser = sender as swf.WebBrowser; //swf.Control host = currentBrowser.Parent; WindowsFormsHost host = currentBrowser.Tag as WindowsFormsHost; if(host == null) { // do some error handle logic } DockPanel dockPanel = host.Parent as DockPanel; //some other work} |
新聞熱點
疑難解答