Gar*_*rry 29 .net wpf interop windowsformshost
我有一个WPF窗口,其中包含一个WindowsFormsHost元素.我需要在这个元素之上绘制东西,但是WindowsFormsHost它的本质意味着它始终位于绘图堆的顶部.由于我无法在WindowsFormsHost组件顶部的同一个WPF窗口中绘制,我可以在其上覆盖另一个窗口吗?
我已经初步尝试了这个,但是我遇到了一些问题:
1)我无法阻止主窗口和覆盖窗口之间的其他应用程序的窗口.
2)当我按Alt-Tab时,覆盖窗口出现在窗口列表中,这非常难看.
基本上我需要一个"子窗口"的概念,并且所有意图和目的的窗口都显示为另一个窗口的一部分.UserControls对我来说不起作用,因为它总是WindowsFormsHost会在它上面绘制.
有任何想法吗?
更新[2011年5月23日10:13]
谢谢你们的回答.
我已经尝试过这种ChildWindow方法,而且WindowsFormsHost元素仍然是最重要的.据我了解,只有一个真正的窗口可以在a上面绘制WindowsFormsHost,同一个窗口中的任何东西都会在下面WindowsFormsHost.
用的元素WindowsFormsHost仍然会在一个WinForms组件画,他们总是画在上面,这似乎非流通...
我想我正在寻找的是一种方法来停靠外部窗口作为主窗口的一部分.在Mac上,有一个真正的"儿童窗口"的概念,我正在寻找类似的东西.
Fre*_*lad 36
我通过使用Popup而不是透明来解决这个问题Window
更新
我最后得到了一个Popup我称之为子类的子类AirspacePopup.
是什么AirspacePopup呢
PlacementTarget.Window它的位置.这个解决方案来自Chris Cavanagh的博客.Popup并设置Margin其子项的负片来实现的.该解决方案来自这个StackOverflow的职位由里克Sladkey这里是一个例子AirspacePopup是用来绘制一个Ellipse上的顶部WebBrowser控制(这实际上是一个WinForms控制),但它会与任何工作一样好WindowsFormsHost.
<Grid>
<local:AirspacePopup PlacementTarget="{Binding ElementName=webBrowser}"
FollowPlacementTarget="True"
AllowOutsideScreenPlacement="True"
ParentWindow="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
IsOpen="True"
AllowsTransparency="True"
Placement="Center"
Width="{Binding ElementName=googleBrowser, Path=ActualWidth}"
Height="{Binding ElementName=googleBrowser, Path=ActualHeight}">
<Grid>
<Ellipse Width="100" Height="100" Fill="Green" Margin="100"/>
</Grid>
</local:AirspacePopup>
<WebBrowser Name="webBrowser" Loaded="WebBrowser_Loaded"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)
简单的代码背后导航..
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void WebBrowser_Loaded(object sender, RoutedEventArgs e)
{
WebBrowser webbrowser = sender as WebBrowser;
webbrowser.Navigate("http://www.stackoverflow.com");
}
}
Run Code Online (Sandbox Code Playgroud)
AirspacePopup
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interop;
public class AirspacePopup : Popup
{
public static readonly DependencyProperty IsTopmostProperty =
DependencyProperty.Register("IsTopmost",
typeof(bool),
typeof(AirspacePopup),
new FrameworkPropertyMetadata(false, OnIsTopmostChanged));
public static readonly DependencyProperty FollowPlacementTargetProperty =
DependencyProperty.RegisterAttached("FollowPlacementTarget",
typeof(bool),
typeof(AirspacePopup),
new UIPropertyMetadata(false));
public static readonly DependencyProperty AllowOutsideScreenPlacementProperty =
DependencyProperty.RegisterAttached("AllowOutsideScreenPlacement",
typeof(bool),
typeof(AirspacePopup),
new UIPropertyMetadata(false));
public static readonly DependencyProperty ParentWindowProperty =
DependencyProperty.RegisterAttached("ParentWindow",
typeof(Window),
typeof(AirspacePopup),
new UIPropertyMetadata(null, ParentWindowPropertyChanged));
private static void OnIsTopmostChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
AirspacePopup airspacePopup = source as AirspacePopup;
airspacePopup.SetTopmostState(airspacePopup.IsTopmost);
}
private static void ParentWindowPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
AirspacePopup airspacePopup = source as AirspacePopup;
airspacePopup.ParentWindowChanged();
}
private bool? m_appliedTopMost;
private bool m_alreadyLoaded;
private Window m_parentWindow;
public AirspacePopup()
{
Loaded += OnPopupLoaded;
Unloaded += OnPopupUnloaded;
DependencyPropertyDescriptor descriptor = DependencyPropertyDescriptor.FromProperty(PlacementTargetProperty, typeof(AirspacePopup));
descriptor.AddValueChanged(this, PlacementTargetChanged);
}
public bool IsTopmost
{
get { return (bool)GetValue(IsTopmostProperty); }
set { SetValue(IsTopmostProperty, value); }
}
public bool FollowPlacementTarget
{
get { return (bool)GetValue(FollowPlacementTargetProperty); }
set { SetValue(FollowPlacementTargetProperty, value); }
}
public bool AllowOutsideScreenPlacement
{
get { return (bool)GetValue(AllowOutsideScreenPlacementProperty); }
set { SetValue(AllowOutsideScreenPlacementProperty, value); }
}
public Window ParentWindow
{
get { return (Window)GetValue(ParentWindowProperty); }
set { SetValue(ParentWindowProperty, value); }
}
private void ParentWindowChanged()
{
if (ParentWindow != null)
{
ParentWindow.LocationChanged += (sender, e2) =>
{
UpdatePopupPosition();
};
ParentWindow.SizeChanged += (sender, e2) =>
{
UpdatePopupPosition();
};
}
}
private void PlacementTargetChanged(object sender, EventArgs e)
{
FrameworkElement placementTarget = this.PlacementTarget as FrameworkElement;
if (placementTarget != null)
{
placementTarget.SizeChanged += (sender2, e2) =>
{
UpdatePopupPosition();
};
}
}
private void UpdatePopupPosition()
{
FrameworkElement placementTarget = this.PlacementTarget as FrameworkElement;
FrameworkElement child = this.Child as FrameworkElement;
if (PresentationSource.FromVisual(placementTarget) != null &&
AllowOutsideScreenPlacement == true)
{
double leftOffset = CutLeft(placementTarget);
double topOffset = CutTop(placementTarget);
double rightOffset = CutRight(placementTarget);
double bottomOffset = CutBottom(placementTarget);
Debug.WriteLine(bottomOffset);
this.Width = Math.Max(0, Math.Min(leftOffset, rightOffset) + placementTarget.ActualWidth);
this.Height = Math.Max(0, Math.Min(topOffset, bottomOffset) + placementTarget.ActualHeight);
if (child != null)
{
child.Margin = new Thickness(leftOffset, topOffset, rightOffset, bottomOffset);
}
}
if (FollowPlacementTarget == true)
{
this.HorizontalOffset += 0.01;
this.HorizontalOffset -= 0.01;
}
}
private double CutLeft(FrameworkElement placementTarget)
{
Point point = placementTarget.PointToScreen(new Point(0, placementTarget.ActualWidth));
return Math.Min(0, point.X);
}
private double CutTop(FrameworkElement placementTarget)
{
Point point = placementTarget.PointToScreen(new Point(placementTarget.ActualHeight, 0));
return Math.Min(0, point.Y);
}
private double CutRight(FrameworkElement placementTarget)
{
Point point = placementTarget.PointToScreen(new Point(0, placementTarget.ActualWidth));
point.X += placementTarget.ActualWidth;
return Math.Min(0, SystemParameters.VirtualScreenWidth - (Math.Max(SystemParameters.VirtualScreenWidth, point.X)));
}
private double CutBottom(FrameworkElement placementTarget)
{
Point point = placementTarget.PointToScreen(new Point(placementTarget.ActualHeight, 0));
point.Y += placementTarget.ActualHeight;
return Math.Min(0, SystemParameters.VirtualScreenHeight - (Math.Max(SystemParameters.VirtualScreenHeight, point.Y)));
}
private void OnPopupLoaded(object sender, RoutedEventArgs e)
{
if (m_alreadyLoaded)
return;
m_alreadyLoaded = true;
if (Child != null)
{
Child.AddHandler(PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(OnChildPreviewMouseLeftButtonDown), true);
}
m_parentWindow = Window.GetWindow(this);
if (m_parentWindow == null)
return;
m_parentWindow.Activated += OnParentWindowActivated;
m_parentWindow.Deactivated += OnParentWindowDeactivated;
}
private void OnPopupUnloaded(object sender, RoutedEventArgs e)
{
if (m_parentWindow == null)
return;
m_parentWindow.Activated -= OnParentWindowActivated;
m_parentWindow.Deactivated -= OnParentWindowDeactivated;
}
private void OnParentWindowActivated(object sender, EventArgs e)
{
SetTopmostState(true);
}
private void OnParentWindowDeactivated(object sender, EventArgs e)
{
if (IsTopmost == false)
{
SetTopmostState(IsTopmost);
}
}
private void OnChildPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
SetTopmostState(true);
if (!m_parentWindow.IsActive && IsTopmost == false)
{
m_parentWindow.Activate();
}
}
protected override void OnOpened(EventArgs e)
{
SetTopmostState(IsTopmost);
base.OnOpened(e);
}
private void SetTopmostState(bool isTop)
{
// Don’t apply state if it’s the same as incoming state
if (m_appliedTopMost.HasValue && m_appliedTopMost == isTop)
{
return;
}
if (Child == null)
return;
var hwndSource = (PresentationSource.FromVisual(Child)) as HwndSource;
if (hwndSource == null)
return;
var hwnd = hwndSource.Handle;
RECT rect;
if (!GetWindowRect(hwnd, out rect))
return;
Debug.WriteLine("setting z-order " + isTop);
if (isTop)
{
SetWindowPos(hwnd, HWND_TOPMOST, rect.Left, rect.Top, (int)Width, (int)Height, TOPMOST_FLAGS);
}
else
{
// Z-Order would only get refreshed/reflected if clicking the
// the titlebar (as opposed to other parts of the external
// window) unless I first set the popup to HWND_BOTTOM
// then HWND_TOP before HWND_NOTOPMOST
SetWindowPos(hwnd, HWND_BOTTOM, rect.Left, rect.Top, (int)Width, (int)Height, TOPMOST_FLAGS);
SetWindowPos(hwnd, HWND_TOP, rect.Left, rect.Top, (int)Width, (int)Height, TOPMOST_FLAGS);
SetWindowPos(hwnd, HWND_NOTOPMOST, rect.Left, rect.Top, (int)Width, (int)Height, TOPMOST_FLAGS);
}
m_appliedTopMost = isTop;
}
#region P/Invoke imports & definitions
#pragma warning disable 1591 //Xml-doc
#pragma warning disable 169 //Never used-warning
// ReSharper disable InconsistentNaming
// Imports etc. with their naming rules
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X,
int Y, int cx, int cy, uint uFlags);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
static readonly IntPtr HWND_TOP = new IntPtr(0);
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
private const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_NOZORDER = 0x0004;
const UInt32 SWP_NOREDRAW = 0x0008;
const UInt32 SWP_NOACTIVATE = 0x0010;
const UInt32 SWP_FRAMECHANGED = 0x0020; /* The frame changed: send WM_NCCALCSIZE */
const UInt32 SWP_SHOWWINDOW = 0x0040;
const UInt32 SWP_HIDEWINDOW = 0x0080;
const UInt32 SWP_NOCOPYBITS = 0x0100;
const UInt32 SWP_NOOWNERZORDER = 0x0200; /* Don’t do owner Z ordering */
const UInt32 SWP_NOSENDCHANGING = 0x0400; /* Don’t send WM_WINDOWPOSCHANGING */
const UInt32 TOPMOST_FLAGS =
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
// ReSharper restore InconsistentNaming
#pragma warning restore 1591
#pragma warning restore 169
#endregion
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
17596 次 |
| 最近记录: |