在 WindowsFormsHost 之上呈现 WPF 控件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5978917/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 22:51:02  来源:igfitidea点击:

Render WPF control on top of WindowsFormsHost

wpfwindowsformshost

提问by Vitalij

I know that default WPF behavior is to render WPF controls and then on top render WinForms, but are there any way to render WPF on top of WindowsFormsHost?

我知道默认的 WPF 行为是呈现 WPF 控件,然后在顶部呈现 WinForms,但是有没有办法在顶部呈现 WPF WindowsFormsHost

Edit: I have found a temp hack as well. When wpf control overlaps WindowsFormsHost, I change the size of the WindowsFormsHost(This only works when you have rectangular object which overlaps, doesn't work for other shapes.)

编辑:我也发现了一个临时黑客。当 wpf 控件重叠时WindowsFormsHost,我更改了的大小WindowsFormsHost(这只适用于重叠的矩形对象,不适用于其他形状。)

采纳答案by CodeNaked

This "airspace" issue is suppose to be fixedin WPF vNext. There are a couple solutions out there, such as here, here, and here.

这个“空域”问题应该在 WPF vNext 中得到修复。有几种解决方案,例如此处此处此处

One way to do this is to host the WPF content in a transparent Popup or Window, which overlays the Interop content.

一种方法是将 WPF 内容托管在透明的弹出窗口或窗口中,它覆盖互操作内容。

回答by chris84948

Late to the party, I know, but I recently came across this issue using a WebBrowser control.

我知道聚会迟到了,但我最近在使用 WebBrowser 控件时遇到了这个问题。

The final fix was to create a screenshot of the web browser whenever I hosted a modal dialog over the top. Since this was a little fiddly, I turned it into a Github project, hopefully this helps a little -

最终的解决方法是每当我在顶部托管一个模态对话框时创建 Web 浏览器的屏幕截图。由于这有点繁琐,我把它变成了一个 Github 项目,希望这会有所帮助 -

https://github.com/chris84948/AirspaceFixer

https://github.com/chris84948/AirspaceFixer

(It's on Nuget too, under AirspaceFixer)

(它也在 Nuget 上,在 AirspaceFixer 下)

Once you have the project all you need to do is this

一旦你有了项目,你需要做的就是这个

xmlns:asf="clr-namespace:AirspaceFixer;assembly=AirspaceFixer"

<asf:AirspacePanel FixAirspace="{Binding FixAirspace}">
    <WebBrowser x:Name="Browser" />
</asf:AirspacePanel>

Where FixAirspaceis the dependency property that switches from the "real" view of the content, to the screenshot or "fake" view.

FixAirspace从内容的“真实”视图切换到屏幕截图或“假”视图的依赖属性在哪里。

回答by AVIDeveloper

Here's a link to the best answer I've seen on this subject so far: Can I overlay a WPF window on top of another?

这是迄今为止在该主题上看到的最佳答案的链接: 我可以将 WPF 窗口叠加在另一个窗口之上吗?

回答by sky-dev

Try this on for size:

试试这个尺寸:

<hacks:AirspaceOverlay>
    <hacks:AirspaceOverlay.OverlayChild>
        <Canvas ToolTip = "A tooltip over a DirectX surface" Background="#01000000" Name="Overlay" />
    </hacks:AirspaceOverlay.OverlayChild>
    <controls:OpenGLControlWrappingWindowsFormsHost />
</hacks:AirspaceOverlay>


// Adapted from http://blogs.msdn.com/b/pantal/archive/2007/07/31/managed-directx-interop-with-wpf-part-2.aspx & http://www.4mghc.com/topics/69774/1/in-wpf-how-can-you-draw-a-line-over-a-windowsformshost
public class AirspaceOverlay : Decorator
{
    private readonly Window _transparentInputWindow;
    private Window _parentWindow;

    public AirspaceOverlay()
    {
        _transparentInputWindow = CreateTransparentWindow();
        _transparentInputWindow.PreviewMouseDown += TransparentInputWindow_PreviewMouseDown;
    }

    public object OverlayChild
    {
        get { return _transparentInputWindow.Content; }
        set { _transparentInputWindow.Content = value; }
    }

    private static Window CreateTransparentWindow()
    {
        var transparentInputWindow = new Window();

        //Make the window itself transparent, with no style.
        transparentInputWindow.Background = Brushes.Transparent;
        transparentInputWindow.AllowsTransparency = true;
        transparentInputWindow.WindowStyle = WindowStyle.None;

        //Hide from taskbar until it becomes a child
        transparentInputWindow.ShowInTaskbar = false;

        //HACK: This window and it's child controls should never have focus, as window styling of an invisible window 
        //will confuse user.
        transparentInputWindow.Focusable = false;

        return transparentInputWindow;
    }

    void TransparentInputWindow_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        _parentWindow.Focus();
    }

    protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
    {
        base.OnRenderSizeChanged(sizeInfo);
        UpdateOverlaySize();
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);
        if (_transparentInputWindow.Visibility != Visibility.Visible)
        {
            UpdateOverlaySize();
            _transparentInputWindow.Show();
            _parentWindow = GetParentWindow(this);
            _transparentInputWindow.Owner = _parentWindow;
            _parentWindow.LocationChanged += ParentWindow_LocationChanged;
            _parentWindow.SizeChanged += ParentWindow_SizeChanged;
        }
    }

    private static Window GetParentWindow(DependencyObject o)
    {
        var parent = VisualTreeHelper.GetParent(o);
        if (parent != null)
            return GetParentWindow(parent);
        var fe = o as FrameworkElement;
        if (fe is Window)
            return fe as Window;
        if (fe != null && fe.Parent != null)
            return GetParentWindow(fe.Parent);  
        throw new ApplicationException("A window parent could not be found for " + o); 
    }

    private void ParentWindow_LocationChanged(object sender, EventArgs e)
    {
        UpdateOverlaySize();
    }

    private void ParentWindow_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        UpdateOverlaySize();
    }

    private void UpdateOverlaySize()
    {
        var hostTopLeft = PointToScreen(new Point(0, 0));
        _transparentInputWindow.Left = hostTopLeft.X;
        _transparentInputWindow.Top = hostTopLeft.Y;
        _transparentInputWindow.Width = ActualWidth;
        _transparentInputWindow.Height = ActualHeight;
    }
}

回答by Tim

If anyone finds themselves unsatisfied with the hacks, setting the Visibility of the WindowsFormsHost to Collapsed or Hidden is always an option.

如果有人发现自己对黑客不满意,将 WindowsFormsHost 的可见性设置为折叠或隐藏始终是一个选项。

回答by Erik

I came across this issue while trying to create a MDI style interface hosting WinForms controls while porting a win forms app to WPF.

我在尝试创建一个托管 WinForms 控件的 MDI 样式界面时遇到了这个问题,同时将一个 win 窗体应用程序移植到 WPF。

I managed to solve it by doing something like this: WindowsFormsHost -> ElementHost -> WindowsFormsHost -> my win forms controls.

我设法通过执行以下操作来解决它:WindowsFormsHost -> ElementHost -> WindowsFormsHost -> 我的 win 表单控件。

Its super ugly, but it creates windows layers for the WPF content to be under the WinForms content.

它超级丑陋,但它为 WPF 内容创建了窗口层,使其位于 WinForms 内容下。