Визуализация элемента управления WPF поверх WindowsFormsHost

Я знаю, что поведение WPF по умолчанию состоит в том, чтобы отображать элементы управления WPF, а затем отображать WinForms поверх, но есть ли способ отображать WPF поверх WindowsFormsHost?

Редактировать: я также нашел временный хак. Когда элемент управления wpf перекрывает WindowsFormsHost, я изменяю размер WindowsFormsHost (это работает только тогда, когда у вас есть прямоугольный объект, который перекрывается, не работает для других фигур).


person Vitalij    schedule 12.05.2011    source источник
comment
Один из способов, который я делаю для этого, - наложение другого окна поверх непрозрачности и прозрачности, работает хорошо, пока используется полноэкранный режим.   -  person Mark Homer    schedule 25.11.2015


Ответы (6)


Эта проблема с "воздушным пространством" предположительно будет исправлена в WPF vNext. Существует несколько решений, таких как здесь, здесь и здесь.

Один из способов сделать это — разместить содержимое WPF в прозрачном всплывающем окне или окне, которое перекрывает содержимое Interop.

person CodeNaked    schedule 12.05.2011
comment
ПРИМЕЧАНИЕ. Я комментирую это как попытку не питать надежды для тех, кто читает это, проблема воздушного пространства в опубликованной статье @CodeNaked имела исправление (hwndhost.IsRedirected), реализованное в бета-версии .NET 4.5, но затем удаленное в финальном выпуске для какая бы ни была причина. Прочитайте это и это - person johnildergleidisson; 15.04.2014
comment
Прозрачное окно на самом деле хорошее решение (хотя все еще хак). Требуется несколько строк кода, чтобы сохранить правильное положение, размер и т. Д., Но, похоже, он работает очень надежно. - person Juho; 13.04.2018

Я знаю, что опоздал на вечеринку, но недавно я столкнулся с этой проблемой, используя элемент управления WebBrowser.

Последнее исправление заключалось в создании снимка экрана веб-браузера всякий раз, когда я размещал модальное диалоговое окно поверх. Поскольку это было немного неудобно, я превратил его в проект Github, надеюсь, это немного поможет -

https://github.com/chris84948/AirspaceFixer

(Это тоже на Nuget, под AirspaceFixer)

Когда у вас есть проект, все, что вам нужно сделать, это

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

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

Где FixAirspace — это свойство зависимости, которое переключается с «реального» представления содержимого на снимок экрана или «поддельное» представление.

person chris84948    schedule 23.11.2016

Вот ссылка на лучший ответ, который я когда-либо видел по этому вопросу: Можно ли наложить окно WPF поверх другого?

person AVIDeveloper    schedule 09.07.2011

Попробуйте это для размера:

<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;
    }
}
person sky-dev    schedule 14.05.2014

Если кто-то окажется неудовлетворенным хаками, всегда можно установить для параметра «Видимость WindowsFormsHost» значение «Свернутый» или «Скрытый».

person Tim    schedule 03.03.2016

Я столкнулся с этой проблемой, пытаясь создать интерфейс в стиле MDI, содержащий элементы управления WinForms, при переносе приложения winforms в WPF.

Мне удалось решить эту проблему, сделав что-то вроде этого: WindowsFormsHost -> ElementHost -> WindowsFormsHost -> элементы управления моими выигрышными формами.

Это очень уродливо, но создает слои Windows для содержимого WPF, которое будет находиться под содержимым WinForms.

person Erik    schedule 04.05.2020