寻找WindowsFormsHost的苦难历程

寻找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楼   

没看懂,看了我还是菜~
闷~
2009-11-25 15:07 |  咖啡色   

#2楼   

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吧。
2009-11-25 16:26 |  周永恒   

#4楼   

引用 周永恒:
通过WinForm寻找WindowsFormsHost,是没什么好方法。
不过这样也没什么意义吧。

WebBrowser对应WinForm的Control,而WindowsFormsHost对应WPF的FrameworkElement。从WPF来看,它的逻辑树到WindowsFormsHost就到头了。从WinFrom来看,WebBrowser需要他的Parent也是个WinForm的Control。


这段解释就足够了,下面的反而说的有点牵强,多了未必就能解释清楚。
呵呵。

其实lz不需要这么麻烦,比较合理的做法是跳过WebBrowser,使用WindowsFormsHost来参与处理逻辑。

1
2
3
4
5
< DockPanel >
    < my:WindowsFormsHost  Name="wfh">
       < swf:WebBrowser  Name="vvv" Tag="{Binding ElementName=wfh}"></ swf:WebBrowser >
    </ my:WindowsFormsHost >
</ DockPanel >


处理逻辑:
1
2
3
4
5
6
7
8
9
10
11
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
}
2009-11-28 14:05 |  winkingzhang   

#5楼[楼主]   

楼上的做法显然更加简洁高效,用一个Tag解决了,值得参考!
2009-11-30 08:33 |  武汉虫虫   

#6楼   

@ winkingzhang
winform控件怎么会有binding?
2016-07-13 10:01 |  HShang   

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值