Максимальное пользовательское окно теряет эффект тени - PullRequest
14 голосов
/ 10 сентября 2011

У меня есть собственное окно 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

Ответы [ 3 ]

23 голосов
/ 29 декабря 2011

Итак, я нашел способ заставить это работать.

Вам нужно использовать библиотеку интеграции оболочки WPF ( здесь ), чтобы выполнить эту работу за вас.Как было написано 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>

* <shell:WindowChrome> - это то место, где вы устанавливаете все различные переменные для взаимодействия.

  • CaptionHeight: это высота области заголовка (панели заголовка), которая позволяетAero snap, двойное нажатие, как в обычной строке заголовка.
  • GlassFrameThickness: установка этого значения в 0,0,0,1 по какой-то причине удаляет хром (стекло), сохраняет квадратную границу и добавляет тень.
  • ResizeBorderThickness: это толщина по краю окна, в которой вы можете изменить размер окна.

Другие замечания, которые следует учитывать при сохранении Window.WindowStyleсвойство равняется SingleBorderWindow и пусть ShellБиблиотека занимается удалением заголовка, кнопок и прочего хрома.

Так что я вроде как потратил впустую свою награду, но похоже, что это вполне жизнеспособное решение, которое приносит удовольствие!

Вот изображение результата: Sample Metro WPF Application

Я также выставил пример проекта на http://code.google.com/p/sample-metro-wpf-application/. Это лицензия MIT, и люди могут использовать ее по своему усмотрению.

16 голосов
/ 10 сентября 2011

Чтобы создать эффект тени при возможности изменения размера формы, попробуйте следующее:

  1. Установите в окне следующие свойства:

    • ResizeMode = "CanResizeWithGrip"
    • AllowsTransparency = "True"
    • WindowStyle = "None"
    • Background = "Transparent"
    • BorderThickness = "3"
  2. После объявления окна добавьте элемент Border

  3. Создать элемент Border.Effect внутри границы
  4. Для эффекта границы добавьте следующее:

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

Это создаст следующее (без поля управления в правом верхнем углу):

enter image description here

Полный 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>
5 голосов
/ 08 октября 2016

Вот некоторый минимальный код, который делает то, что вам нужно.

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

Это окно ведет себя как обычное окно в том смысле, что оно может быть:

  • изменено с помощью его краев
  • перетаскивается в области заголовка
  • щелкните правой кнопкой мыши область заголовка, чтобы отобразить системное меню
  • развернуто / восстановлено двойным щелчком области заголовка
  • snappedпо сторонам экрана путем перетаскивания или использования горячих клавиш (Win 10)

У него также есть тень.


Конечный результат выглядит следующим образом:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...