注意:这不是关于无边窗的问题。
所以,当我在Windows 7上探索我的“开始”菜单时,我偶然发现了这个程序:
它是一个原生Windows程序,名为"数学输入面板。"现在,我对窗户的形状感到好奇。我知道它并没有被DWM完全绘制,因为边框和关闭按钮看起来很腥,窗口没有阴影(我启用了阴影)。我对这是如何制作的第一个猜测是使用DwmEnableBlurBehindWindow
,但是我无法想象它是否适用于不规则的窗口形状,是吗? (或者还有另一种方法可以做到这一点,还是完全是微软的巫术?)
答案 0 :(得分:4)
这是一个快速入侵的WPF解决方案。它使用DWM_BLURBEHIND
结构的hRgnBlur
和一些互操作。
此示例将在窗口上应用椭圆形背景模糊。
您可以轻松地将其转换为MVVM友好性的附加属性或行为。听取WM_DWMCOMPOSITIONCHANGED
消息并在需要时重新应用模糊也是一个好主意。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
WindowStyle = WindowStyle.None;
AllowsTransparency = true;
SourceInitialized += OnSourceInitialized;
}
private void OnSourceInitialized(object sender, EventArgs eventArgs)
{
if (!NativeMethods.DwmIsCompositionEnabled())
return;
var hwnd = new WindowInteropHelper(this).Handle;
var hwndSource = HwndSource.FromHwnd(hwnd);
var sizeFactor = hwndSource.CompositionTarget.TransformToDevice.Transform(new Vector(1.0, 1.0));
Background = System.Windows.Media.Brushes.Transparent;
hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent;
using (var path = new GraphicsPath())
{
path.AddEllipse(0, 0, (int)(ActualWidth * sizeFactor.X), (int)(ActualHeight * sizeFactor.Y));
using (var region = new Region(path))
using (var graphics = Graphics.FromHwnd(hwnd))
{
var hRgn = region.GetHrgn(graphics);
var blur = new NativeMethods.DWM_BLURBEHIND
{
dwFlags = NativeMethods.DWM_BB.DWM_BB_ENABLE | NativeMethods.DWM_BB.DWM_BB_BLURREGION | NativeMethods.DWM_BB.DWM_BB_TRANSITIONONMAXIMIZED,
fEnable = true,
hRgnBlur = hRgn,
fTransitionOnMaximized = true
};
NativeMethods.DwmEnableBlurBehindWindow(hwnd, ref blur);
region.ReleaseHrgn(hRgn);
}
}
}
[SuppressUnmanagedCodeSecurity]
private static class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
public struct DWM_BLURBEHIND
{
public DWM_BB dwFlags;
public bool fEnable;
public IntPtr hRgnBlur;
public bool fTransitionOnMaximized;
}
[Flags]
public enum DWM_BB
{
DWM_BB_ENABLE = 1,
DWM_BB_BLURREGION = 2,
DWM_BB_TRANSITIONONMAXIMIZED = 4
}
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern bool DwmIsCompositionEnabled();
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind);
}
}
与以下XAML一起使用:
<Window x:Class="WpfTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="300" WindowStartupLocation="CenterScreen">
<Border Background="#800000FF" Margin="30">
<TextBlock Text="Hello, world!" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Border>
</Window>
结果是:
答案 1 :(得分:2)
所以,我不知道,hRgn
可以采取不规则的形状(而DwmEnableBlurBehindWindow
需要hRgn
,但我知道这一点。所以,这是我的解决方案(或多或少)与WPF兼容:
...和源代码:
MainWindow.xaml:
<Window x:Class="IrregularGlassWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="500"
Width="500"
Background="#01FFFFFF"
AllowsTransparency="True"
WindowStyle="None"
ResizeMode="NoResize">
<Window.Clip>
<PathGeometry>
<PathFigure StartPoint="250,0">
<ArcSegment Point="250,500"
RotationAngle="180"
Size="250,250"
SweepDirection="Clockwise" />
<ArcSegment Point="250,0"
RotationAngle="180"
Size="250,250"
SweepDirection="Clockwise" />
</PathFigure>
</PathGeometry>
</Window.Clip>
<Grid>
<Ellipse Margin="1"
Width="498"
Height="498"
Stroke="#8FFF"
StrokeThickness="1.25" />
<Ellipse Width="500"
Height="500"
Stroke="#C000"
StrokeThickness="1"/>
</Grid>
</Window>
MainWindow.xaml.cs:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
this.SourceInitialized += MainWindow_SourceInitialized;
this.KeyDown += MainWindow_KeyDown;
}
void MainWindow_KeyDown(object sender, KeyEventArgs e) {
if (e.Key == Key.Escape) this.Close();
}
void MainWindow_SourceInitialized(object sender, EventArgs e) {
var helper = new WindowInteropHelper(this);
var hwnd = helper.Handle;
var src = HwndSource.FromHwnd(hwnd);
src.CompositionTarget.BackgroundColor = Colors.Transparent;
WindowChrome.SetWindowChrome(this, new WindowChrome {
CaptionHeight = 500,
CornerRadius = new CornerRadius(0),
GlassFrameThickness = new Thickness(0),
NonClientFrameEdges = NonClientFrameEdges.None,
ResizeBorderThickness = new Thickness(0),
UseAeroCaptionButtons = false
});
GraphicsPath path = new GraphicsPath(FillMode.Alternate);
path.StartFigure();
path.AddArc(new RectangleF(0, 0, 500, 500), 0, 360);
path.CloseFigure();
var dbb = new DwmBlurBehind(true);
dbb.SetRegion(Graphics.FromHwnd(hwnd), new Region(path));
DwmApi.DwmEnableBlurBehindWindow(hwnd, ref dbb);
}
}
我认为有人打败了我,但这就是我的解决方案的工作原理:
当窗口的SourceInitialized
事件被触发时,这意味着我们有一个窗口的句柄。所以在这个函数的处理程序中,我得到了窗口句柄。然后我调用从dwmapi.dll导入的函数DwmEnableBlurBehindWindow
。这基本上将窗户的透明区域变成某个区域的玻璃。我从pinvoke.net获得的DwmBlurBehind
结构,它将GDI + System.Drawing.Region
转换为hRgn
。 hRgn
传递给DwmEnableBlurBehindWindow
,并将透明部分剪切为Region
。在这种情况下,我用了一个圆圈。然后XAML只是重音边框。值得注意的是,出于某种原因,将Window.Background
设置为Transparent
时,如果AllowsTransparency
为真,则无法启用命中测试。不知道为什么,但它可能与代码隐藏有关。
答案 2 :(得分:0)
这只是两个试图模拟DWM的无边界窗口。这可以通过带有阴影和“腥”关闭按钮的主题不一致以及右“子窗口”的渐变中断来证明。一个简单的DWM查询将给出正确的提示,以正确显示窗口。
因为两个窗口都完全是正方形,所以没有“涉及到的魔法”。 主窗口具有与之关联的形状,导致插入按钮出现,而底部的其余部分显示为半透明。 使用GDI +或WPF可以达到相同的效果。
我要澄清原始效果是如何产生的,而不是复制它的方法。先前的答案已成功证明了这一点。