WPF 中 WindowsFormsHost 之 AirspacePanel
项目中使用WPF开发客户端,系统需要内嵌C++开发的控件,在WPF中内嵌Winfrom或者Win32K控件都需要 包裹在 WindowsFormsHost 中,很顺利的将控件显示出来。如下:
后续开发中,需要在当前页面,开发一个弹框功能。如下:
So ! ! !
弹出框被遮挡了,查了资料在 https://github.com/chris84948/AirspaceFixer 找到其中一种解决方案,该方案是在弹出框之前设置 WindowsFormsHost 显示一张截图替代,关闭弹出框之后替换回来。
具体实现如下:
1 internal class AirspacePanel : System.Windows.Controls.ContentControl 2 { 3 public static readonly DependencyProperty FixAirspaceProperty = 4 DependencyProperty.Register("FixAirspace", 5 typeof(bool), 6 typeof(AirspacePanel), 7 new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnFixAirspaceChanged))); 8 9 public bool FixAirspace 10 { 11 get { return (bool)GetValue(FixAirspaceProperty); } 12 set { SetValue(FixAirspaceProperty, value); } 13 } 14 15 16 private System.Windows.Controls.Image _airspaceScreenshot; 17 private System.Windows.Controls.ContentControl _airspaceContent; 18 private float _scalingFactor; 19 20 static AirspacePanel() 21 { 22 DefaultStyleKeyProperty.OverrideMetadata(typeof(AirspacePanel), new FrameworkPropertyMetadata(typeof(AirspacePanel))); 23 } 24 25 public AirspacePanel() 26 { 27 Loaded += (_, __) => GetScalingFactor(); 28 } 29 30 public override void OnApplyTemplate() 31 { 32 base.OnApplyTemplate(); 33 34 _airspaceContent = GetTemplateChild("PART_AirspaceContent") as ContentControl; 35 _airspaceScreenshot = GetTemplateChild("PART_AirspaceScreenshot") as System.Windows.Controls.Image; 36 } 37 38 private static void OnFixAirspaceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 39 { 40 var panel = d as AirspacePanel; 41 42 43 44 if (panel == null || panel.ActualWidth == 0 || panel.ActualHeight == 0 || PresentationSource.FromVisual(panel) == null) 45 return; 46 47 if ((bool)e.NewValue) 48 { 49 50 panel._airspaceContent.Visibility = Visibility.Hidden; 51 panel._airspaceScreenshot.Visibility = Visibility.Visible; 52 } 53 else 54 { 55 panel._airspaceContent.Visibility = Visibility.Visible; 56 panel._airspaceScreenshot.Visibility = Visibility.Hidden; 57 panel._airspaceScreenshot.Source = null; 58 } 59 } 60 61 62 private void CreateScreenshotFromContent() 63 { 64 System.Windows.Point upperLeftPoint = _airspaceContent.PointToScreen(new System.Windows.Point(0, 0)); 65 var bounds = new System.Drawing.Rectangle((int)(upperLeftPoint.X * _scalingFactor), 66 (int)(upperLeftPoint.Y * _scalingFactor), 67 (int)(_airspaceContent.RenderSize.Width * _scalingFactor), 68 (int)(_airspaceContent.RenderSize.Height * _scalingFactor)); 69 70 using (var bitmap = new System.Drawing.Bitmap((int)bounds.Width, (int)bounds.Height)) 71 { 72 using (var g = System.Drawing.Graphics.FromImage(bitmap)) 73 { 74 g.CopyFromScreen(new System.Drawing.Point(bounds.Left, bounds.Top), 75 System.Drawing.Point.Empty, 76 new System.Drawing.Size((int)bounds.Width, (int)bounds.Height)); 77 } 78 79 _airspaceScreenshot.Source = GetImageSourceFromBitmap(bitmap); 80 } 81 } 82 83 84 [DllImport("gdi32.dll")] 85 static extern int GetDeviceCaps(IntPtr hdc, int nIndex); 86 private void GetScalingFactor() 87 { 88 var g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero); 89 IntPtr desktop = g.GetHdc(); 90 int LogicalScreenHeight = GetDeviceCaps(desktop, 10); 91 int PhysicalScreenHeight = GetDeviceCaps(desktop, 117); 92 93 float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight; 94 95 _scalingFactor = ScreenScalingFactor; // 1.25 = 125% 96 } 97 98 public ImageSource GetImageSourceFromBitmap(System.Drawing.Bitmap bitmap) 99 { 100 using (var memory = new MemoryStream()) 101 { 102 bitmap.Save(memory,ImageFormat.Png); 103 memory.Position = 0; 104 System.Windows.Media.Imaging.BitmapImage bitmapImage = new BitmapImage(); 105 bitmapImage.BeginInit(); 106 bitmapImage.StreamSource = memory; 107 bitmapImage.CacheOption = BitmapCacheOption.OnLoad; 108 bitmapImage.EndInit(); 109 return bitmapImage; 110 } 111 } 112 }
设置样式:
1 <Style TargetType="{x:Type dwayneneed:AirspacePanel}"> 2 <Setter Property="Template"> 3 <Setter.Value> 4 <ControlTemplate TargetType="{x:Type dwayneneed:AirspacePanel}"> 5 6 <Grid HorizontalAlignment="{TemplateBinding HorizontalAlignment}" 7 VerticalAlignment="{TemplateBinding VerticalAlignment}"> 8 <Image x:Name="PART_AirspaceScreenshot" 9 Visibility="Hidden" /> 10 11 <ContentControl x:Name="PART_AirspaceContent" 12 Content="{TemplateBinding Content}" /> 13 </Grid> 14 15 </ControlTemplate> 16 </Setter.Value> 17 </Setter> 18 </Style>
包裹 WindowsFormsHost
<AirspacePanel x:Name="airspacePanel" FixAirspace="{Binding FixAirspace}"> <WindowsFormsHost x:Name="host" Visibility="Visible" /> </AirspacePanel>
弹窗之前设置
FixAirspace=true;
弹窗之后设置
FixAirspace=false;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现