o_xaml_studio.jpg

一、背景

  WPF的原生控件并不具备自身的句柄,即使使用偏门的方式获取的结果也都是控件所在窗体的句柄,并不代表该控件本身的资源,这是由WPF的自身的机制决定的。

IntPtr hwnd = new WindowInteropHelper(this).Handle; //this就是要获取句柄的窗体的类名;

IntPtr hwnd = ((HwndSource)PresentationSource.FromVisual(uielement)).Handle;//uielement就是要获取句柄的控件,该控件必须继承自UIElement。

  到此需要了解下Winform与WPF的区别,WPF和winform最大的区别在于WPF底层使用的DirectX,winform底层使用的是GDI+,所以WPF的图形界面上更胜一筹。

  • GDI+(Graphics Device Interface)图形设备接口,它的主要任务是负责绘图程序之间的信息交换、处理,所有windows程序的图形输出
  • DirectX(Direct Extension)多媒体编程接口,加强3D图形和声音效果,有很多API组成。按照性质分类可分为四大部分:显示部分,声音部分,输入部分和网络部分

二、应时而生WindowFormsHost

  当我们直接使用WPF的控件句柄作为OSG等第三方控件的绘制视图区域时,我们会发现视图区域占据了整个窗体,这与上面提到的WPF的原生控件并不具备自身的句柄的结论一致。

  为解决上述问题,在WPF中嵌入第三方控件时,往往需要借助WindowFormsHost控件,使用该控件可以包裹Winform控件,再将Winform的句柄暴露给第三方控件,即可实现在指定区域进行类似OSG视图的绘制。

<Window x:Class="WpfTutorialSamples.Misc_controls.WindowsFormsHostSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
        Title="WindowsFormsHostSample" Height="350" Width="450">
    <Grid>
        <WindowsFormsHost Name="wfhSample">//使用WindowsFormsHost包裹Winform控件
            <WindowsFormsHost.Child>
                <wf:WebBrowser DocumentTitleChanged="wbWinForms_DocumentTitleChanged" />
            </WindowsFormsHost.Child>
        </WindowsFormsHost>
    </Grid>
</window>

三、WindowFormsHost的置顶缺陷

  在WPF中调用windowFormsHost的控件时,由于渲染机制的问题总会出现各种问题,让许多人纠结头疼的便是:windowFormsHost控件在一个位置时会优先显示,而且完全设置不了顺序,永远在最上边,WPF原生的控件无法对其遮盖,更别说透明了

四、解决WindowFormsHost的置顶问题

  经过层层排除和筛选,最终找到一个可行方案:Microsoft.DwayneNeed

  1. 访问:https://microsoftdwayneneed.codeplex.com/SourceControl/latest
  2. 下载源码
  3. 使用VS打开Microsoft.DwayneNeed.sln解决方案
  4. 完成编译
  5. 在WPF项目中添加Microsoft.DwayneNeed.dll引用
  6. 在xaml中添加

    xmlns:interop="clr-namespace:Microsoft.DwayneNeed.Interop;assembly=Microsoft.DwayneNeed
  7. 在xaml中使用AirspaceDecorator包裹WindowsFormsHost

    <interop:AirspaceDecorator AirspaceMode="Redirect" Background="White" IsInputRedirectionEnabled="True" IsOutputRedirectionEnabled="True">
       <WindowsFormsHost x:Name="windowsFormsHost1" Visibility="Visible" />
    </interop:AirspaceDecorator>
  8. 完整例子如下:

    <Window x:Class="Toll.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:interop="clr-namespace:Microsoft.DwayneNeed.Interop;assembly=Microsoft.DwayneNeed"
        xmlns:local="clr-namespace:Toll"
        mc:Ignorable="d"
        Title="MainWindow" Width="1500" Height="800" Closing="Window_Closing">
    <Grid Name="root">
        <interop:AirspaceDecorator AirspaceMode="Redirect" Background="White" IsInputRedirectionEnabled="True" IsOutputRedirectionEnabled="True">
            <WindowsFormsHost x:Name="windowsFormsHost1" Visibility="Visible" />
        </interop:AirspaceDecorator>
        <Ellipse Width="100" Height="100" Fill="Green" Margin="100"/>
    </Grid>
    </Window>
文章目录