最大自定义窗口失去投影效果

发布于 2024-12-03 18:01:21 字数 2437 浏览 2 评论 0原文

我有一个自定义 WPF 窗口定义为:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" MinHeight="300" Height="350" MinWidth="600" Width="700"      ResizeMode="CanResizeWithGrip" AllowsTransparency="True" WindowStyle="None">

我在网上找到了一个可以创建阴影的类,如下所示。即使使用调整大小手柄,这也很有效,直到我最大化窗口。一旦我最大化窗口或更改另一个窗口(例如 Visual Studio)的窗口状态,我就会失去阴影并且无法将其恢复。有什么想法吗?


投影类:

Public Class DropShadow

Private Shared _handler As EventHandler = New EventHandler(AddressOf window_SourceInitialized)

<DllImport("dwmapi.dll", PreserveSig:=True)> _
Private Shared Function DwmSetWindowAttribute(hwnd As IntPtr, attr As Integer, ByRef attrValue As Integer, attrSize As Integer) As Integer

End Function

<DllImport("dwmapi.dll")> _
Private Shared Function DwmExtendFrameIntoClientArea(hWnd As IntPtr, ByRef pMarInset As Margins) As Integer
End Function

Public Shared Sub DropShadowToWindow(window As Window)
    If Not DropShadow(window) Then
        AddHandler window.SourceInitialized, _handler
        AddHandler window.SizeChanged, New SizeChangedEventHandler(AddressOf windowSizeChanged)
    End If
End Sub

Private Shared Sub window_SourceInitialized(sender As Object, e As EventArgs)
    Dim window As Window = DirectCast(sender, Window)

    DropShadow(window)

    RemoveHandler window.SourceInitialized, _handler
End Sub


Private Shared Function DropShadow(window As Window) As Boolean
    Try
        Dim helper As New WindowInteropHelper(window)
        Dim val As Integer = 2
        Dim ret1 As Integer = DwmSetWindowAttribute(helper.Handle, 2, val, 4)

        If ret1 = 0 Then
            Dim m As New Margins() With { _
             .Bottom = 0, _
             .Left = 0, _
             .Right = 0, _
             .Top = 0 _
            }
            Dim ret2 As Integer = DwmExtendFrameIntoClientArea(helper.Handle, m)
            Return ret2 = 0
        Else
            Return False
        End If
    Catch ex As Exception
        ' Probably dwmapi.dll not found (incompatible OS)
        Return False
    End Try
End Function

Private Shared Sub windowSizeChanged(sender As Object, e As SizeChangedEventArgs)
    Dim window As Window = DirectCast(sender, Window)
    DropShadow(window)
End Sub
End Class

I have a custom WPF window defined as:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" MinHeight="300" Height="350" MinWidth="600" Width="700"      ResizeMode="CanResizeWithGrip" AllowsTransparency="True" WindowStyle="None">

I found a class online that creates drop shadows, shown below. This works well, even with a resize grip, until I maximise the window. Once I maximise the window or change the window state of another window (eg. Visual Studio), I loose the drop shadow and I cannot get it back. Any Ideas?


Drop Shadow Class:

Public Class DropShadow

Private Shared _handler As EventHandler = New EventHandler(AddressOf window_SourceInitialized)

<DllImport("dwmapi.dll", PreserveSig:=True)> _
Private Shared Function DwmSetWindowAttribute(hwnd As IntPtr, attr As Integer, ByRef attrValue As Integer, attrSize As Integer) As Integer

End Function

<DllImport("dwmapi.dll")> _
Private Shared Function DwmExtendFrameIntoClientArea(hWnd As IntPtr, ByRef pMarInset As Margins) As Integer
End Function

Public Shared Sub DropShadowToWindow(window As Window)
    If Not DropShadow(window) Then
        AddHandler window.SourceInitialized, _handler
        AddHandler window.SizeChanged, New SizeChangedEventHandler(AddressOf windowSizeChanged)
    End If
End Sub

Private Shared Sub window_SourceInitialized(sender As Object, e As EventArgs)
    Dim window As Window = DirectCast(sender, Window)

    DropShadow(window)

    RemoveHandler window.SourceInitialized, _handler
End Sub


Private Shared Function DropShadow(window As Window) As Boolean
    Try
        Dim helper As New WindowInteropHelper(window)
        Dim val As Integer = 2
        Dim ret1 As Integer = DwmSetWindowAttribute(helper.Handle, 2, val, 4)

        If ret1 = 0 Then
            Dim m As New Margins() With { _
             .Bottom = 0, _
             .Left = 0, _
             .Right = 0, _
             .Top = 0 _
            }
            Dim ret2 As Integer = DwmExtendFrameIntoClientArea(helper.Handle, m)
            Return ret2 = 0
        Else
            Return False
        End If
    Catch ex As Exception
        ' Probably dwmapi.dll not found (incompatible OS)
        Return False
    End Try
End Function

Private Shared Sub windowSizeChanged(sender As Object, e As SizeChangedEventArgs)
    Dim window As Window = DirectCast(sender, Window)
    DropShadow(window)
End Sub
End Class

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

客…行舟 2024-12-10 18:01:21

所以我找到了一种方法来让它发挥作用。

您需要使用 WPF Shell 集成库(此处)来为您完成这项工作。由于它是由 MS 编写的,他们已经修复了(看起来)对 P/Invoke 代码执行的任何问题。

因此,很容易得到一个没有 Aero 玻璃、边缘可调整大小、具有 Aero 捕捉行为的标题区域以及在最小/最大后重新出现的阴影的窗口。

这是我的窗口的代码(注意,您需要引用 Microsoft.Windows.Shell

<Window x:Class="MyLibrary.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell"
        Title="MainWindow"
        WindowStyle="SingleBorderWindow"
        ResizeMode="CanResizeWithGrip"
        mc:Ignorable="d"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        d:DesignHeight="449"
        d:DesignWidth="677"
        Foreground="White"
        Background="Black">

    <shell:WindowChrome.WindowChrome>
        <shell:WindowChrome CaptionHeight="35"
                            GlassFrameThickness="0,0,0,1"
                            ResizeBorderThickness="5" />
    </shell:WindowChrome.WindowChrome>

    <Grid x:Name="LayoutRoot">

    </gGrid>
</Window>

是您设置所有不同变量的位置用于互操作。

  • CaptionHeight:这是标题区域(标题栏)的高度,允许像普通标题栏一样进行 Aero 捕捉、双击行为。
  • GlassFrameThickness:出于某种原因将其设置为 0,0,0,1 会删除镀铬(玻璃),保留方形边框,并添加阴影。
  • ResizeBorderThickness:这是窗口边缘的厚度,您可以在此处调整窗口大小。

其他需要注意的事项是,您应将 Window.WindowStyle 属性保持为 SingleBorderWindow 并让 Shell 库处理删除标题、按钮和其他镶边的操作。

所以我在那里浪费了我的赏金,但它看起来是一个完全可行的解决方案,非常有效!

编辑:

这是结果的图片: Sample Metro WPF Application

我还在 http://code.google.com/p/sample-metro-wpf-application/。这是麻省理工学院的许可证,人们可以随心所欲地使用它。

So I found out a way to get this to work.

You need to use the WPF Shell Integration Library (here) to do the work for you. As it's been written by MS, they have fixed (it seems) any issues with doing to the P/Invoke code.

So it is easy to get a Window that has no Aero glass, is resizable on the edges, has a caption area that behaves with Aero snap, and has a drop shadow that reappears after min/maxing.

This is the code for my window (note, you need to have referenced Microsoft.Windows.Shell)

<Window x:Class="MyLibrary.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell"
        Title="MainWindow"
        WindowStyle="SingleBorderWindow"
        ResizeMode="CanResizeWithGrip"
        mc:Ignorable="d"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        d:DesignHeight="449"
        d:DesignWidth="677"
        Foreground="White"
        Background="Black">

    <shell:WindowChrome.WindowChrome>
        <shell:WindowChrome CaptionHeight="35"
                            GlassFrameThickness="0,0,0,1"
                            ResizeBorderThickness="5" />
    </shell:WindowChrome.WindowChrome>

    <Grid x:Name="LayoutRoot">

    </gGrid>
</Window>

The <shell:WindowChrome> is where you set all the different variables for the interop.

  • CaptionHeight: This is the height of the caption area (headerbar) that allows for the Aero snap, double clicking behaviour as a normal title bar does.
  • GlassFrameThickness: Setting this to 0,0,0,1 for some reason removes the chrome (glass), keeps the square border, and adds a drop shadow.
  • ResizeBorderThickness: This is thickness at the edge of the window which is where you can resize the window.

Other things to note as that you keep the Window.WindowStyle property equal to SingleBorderWindow and let the Shell Library deal with removing the title, buttons and other chrome.

So I kinda wasted my bounty there, but it looks like a completely viable solution that works a treat!

EDIT:

Here is a picture of the result: Sample Metro WPF Application

I also put up a sample project on http://code.google.com/p/sample-metro-wpf-application/. It's an MIT license and people can use it however they want.

二货你真萌 2024-12-10 18:01:21

要创建阴影效果,同时能够调整表单大小,请尝试以下操作:

  1. 在窗口上设置以下属性:

    • ResizeMode="CanResizeWithGrip"
    • AllowsTransparency="True"
    • WindowStyle="无"
    • 背景=“透明”
    • BorderThickness="3"
  2. 在窗口声明后,添加 Border 元素

  3. 在边框内部创建一个 Border.Effect 元素
  4. 用于边框效果添加以下:

    >
    

这将创建以下内容(右上角没有控制框):

在此处输入图像描述

完整的 XAML:

<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" MinHeight="500" Height="350" MinWidth="300" Width="700" ResizeMode="CanResizeWithGrip" AllowsTransparency="True" WindowStyle="None" Background="White" BorderThickness="3">
<Border>
    <Border.Effect>
        <DropShadowEffect BlurRadius="5" Color="Black" Opacity="0.8" ShadowDepth="0.5" />
    </Border.Effect>
                      <!-- Put your content in here -->
</Border>
</Window>

To create a drop shadow effect whilst having the ability to re-size the form try the following:

  1. Set the following properties on the window:

    • ResizeMode="CanResizeWithGrip"
    • AllowsTransparency="True"
    • WindowStyle="None"
    • Background="Transparent"
    • BorderThickness="3"
  2. After the window declaration, add a Border element

  3. Create a Border.Effect element inside of the border
  4. For the border effect add the following:

    <DropShadowEffect BlurRadius="5" Color="Black" Opacity="0.8" ShadowDepth="0.5" />
    

This will create the following (without the control box in the top right):

enter image description here

Full XAML:

<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" MinHeight="500" Height="350" MinWidth="300" Width="700" ResizeMode="CanResizeWithGrip" AllowsTransparency="True" WindowStyle="None" Background="White" BorderThickness="3">
<Border>
    <Border.Effect>
        <DropShadowEffect BlurRadius="5" Color="Black" Opacity="0.8" ShadowDepth="0.5" />
    </Border.Effect>
                      <!-- Put your content in here -->
</Border>
</Window>
少女情怀诗 2024-12-10 18:01:21

这是一些可以完成您所追求的任务的最小代码。

<Window x:Class="WindowChromeSpike.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <WindowChrome.WindowChrome>
    <WindowChrome GlassFrameThickness="0,0,0,1" CornerRadius="0" />
  </WindowChrome.WindowChrome>

  <!-- window contents: just a blue rectangle for demo purposes -->
  <Border Background="#0093C0" />

</Window>

该窗口的行为类似于普通窗口,因为它可以:

  • 其边缘来调整
  • 通过在标题区域内拖动
  • 大小 右键单击​​标题区域以显示系统菜单
  • 通过双击标题区域来最大化/恢复 贴
  • 靠到屏幕两侧拖动或使用热键(Win 10)

它还有一个投影。


最终结果如下所示:

在此处输入图像描述

Here's some minimal code that does what you're after.

<Window x:Class="WindowChromeSpike.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <WindowChrome.WindowChrome>
    <WindowChrome GlassFrameThickness="0,0,0,1" CornerRadius="0" />
  </WindowChrome.WindowChrome>

  <!-- window contents: just a blue rectangle for demo purposes -->
  <Border Background="#0093C0" />

</Window>

This window behaves like a usual window in that it can be:

  • resized via its edges
  • dragged within the title area
  • right-clicked the title area to show the system menu
  • maximised/restored by double clicking the title area
  • snapped to the sides of your screens by dragging or using hotkeys (Win 10)

It also has a drop shadow.


The end result looks like this:

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文