【问题标题】:Maximum custom window loses drop shadow effect最大自定义窗口失去投影效果
【发布时间】:2011-11-14 05:01:34
【问题描述】:

我有一个自定义 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

【问题讨论】:

  • 调试的时候,DropShadow的第一个返回值是多少?如果它返回 False,则不会连接事件处理程序,并且当您调整它的大小时 DS 将消失。
  • 它正确设置了处理程序。我决定删除它并尝试不同的方式。我稍后会发布我的做法......

标签: wpf vb.net xaml window


【解决方案1】:

这里有一些最小的代码,可以满足您的需求。

<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)

它还有一个投影。


最终结果如下所示:

【讨论】:

  • 你是如何给窗口添加阴影效果的?这是您需要添加阴影的唯一代码还是与 OP 发布的代码一起?
【解决方案2】:

所以我找到了一种让它工作的方法。

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

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

这是我的窗口的代码(注意,你需要引用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>

&lt;shell:WindowChrome&gt; 是您为互操作设置所有不同变量的位置。

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

其他需要注意的事项,保持 Window.WindowStyle 属性等于 SingleBorderWindow 并让 Shell 库处理删除标题、按钮和其他镶边。

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

编辑:

这是结果的图片:

我还在http://code.google.com/p/sample-metro-wpf-application/ 上发布了一个示例项目。这是 MIT 许可证,人们可以随意使用它。

【讨论】:

  • 感谢您的额外回答。您能否发布代码图片以显示最终的外观。将帮助其他返回此线程的人:)
  • 当然...我会尽快拍张照片。
  • @StuartBlackler:我添加了图片和示例项目的链接。
  • 请注意,如果您不想看到夹点,可以使用 ResizeMode 的 CanResize 选项。
  • 现在您不需要 Microsoft.Windows.Shell 包。该课程在PresentationFramework.dll 中为System.Windows.Shell.WindowChrome
【解决方案3】:

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

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

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

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

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

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

完整的 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>

【讨论】:

  • 这些选项对我不起作用... Stuart Blackler 你能张贴上图的整个 XAML 吗?
  • 我相信我唯一没有包括的部分是按钮。我会看看能不能找到项目,但我不能保证,对不起。
  • 我从头开始创建了一个新项目......它工作......我只想看到按钮......我使用Webdings字体创建它们......你怎么样创建?顺便提一下BorderThickness 的想法!谢谢!!!!!! :)
  • 这对我有用,但有一点需要注意。我的窗口是通过单击托盘图标以编程方式打开的,并且在最小化然后最大化一次之前不显示边框。为了在显示窗口的代码中解决这个问题,我做了(管道表示新行): theWindow = New MainWindow() |窗口.Show() | theWindow.Visibility = Visibility.Hidden | theWindow.Visibility = Visibility.Visible
  • 这可行,但是在最小化到任务栏并从任务栏恢复时会丢失窗口动画。知道如何重新实现它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-02
  • 2014-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多