2013-05-11 4 views
13

Я пытаюсь отбросить тень вокруг всей формы, как и в первом изображении, за исключением того, что это WPF, а не WinForm. теперь я хочу оставить ту же тень на winform.Drop Shadow On Borderless WinForm

Это то, что я want..¬

Windows Form Shadow

Не this..¬

Windows Form Shadow

+0

http://stackoverflow.com/questions/3372303/dropshadow-for-wpf-borderless-window –

+0

Вы видели эту ссылку http://stackoverflow.com/questions/2463519/drop-shadow-in -winforms-controls, пытаясь переопределить createparams? – Edper

+1

@ Верхнее переопределение cp даст тень во втором изображении –

ответ

0

Насколько я знаю, нет никакого прямого способа сделать это в WinForms.

Вместо этого, вы можете следовать шаг за шагом:

1) Создание изображения, имеющего нужную тень падения с помощью Photoshop или любой другой инструмент.
2) Используйте это изображение в качестве фонового рисунка формы.
3) Устанавливает свойство FormBorderStyle формы в None.
4) Все готово!
5) Примечание. Обязательно сохраните изображение в правильном формате (например, png), чтобы эффект отбрасывания мог работать.

+1

Это можно сделать в WinForms. Это достигается с помощью многоуровневых окон. –

+0

@ByteBlast вы можете продумать, чтобы мы могли чувствовать себя просветленным ... Метод, который я обсуждал выше, является одним из нескольких возможных способов. –

+0

«В WinForms нет прямого способа сделать это». –

32

В WinForms вы можете просто переопределить защищенное формой свойство CreateParams и добавить флаг CS_DROPSHADOW к стилям классов. Например:

public class ShadowedForm : Form { 
    protected override CreateParams CreateParams { 
     get { 
      const int CS_DROPSHADOW = 0x20000; 
      CreateParams cp = base.CreateParams; 
      cp.ClassStyle |= CS_DROPSHADOW; 
      return cp; 
     } 
    } 

    // ... other code ... 
} 

Но, пара предостережений & hellip;

  1. Этот флаг работает только на окнах верхнего уровня. В Win32-talk это означает перекрывающиеся и всплывающие окна. Он не влияет на дочерние окна (например, элементы управления). Я думал, что я где-то слышал, что это ограничение было удалено из Windows 8, но я не могу найти ссылку, подтверждающую это, и у меня нет Windows 8 для тестирования.

  2. Возможно, пользователь полностью отключил эту функцию. Если это так, вы не получите тени для теней, независимо от того, как вы их просите. Это по дизайну. Ваше приложение не должно пытаться переопределить этот запрос. Вы можете определить, включены ли тени или отключены с помощью P/Вызов функции SystemParametersInfo и передачи флага SPI_GETDROPSHADOW.

  3. Тема Aero также добавляет тени в окна верхнего уровня. Этот эффект является отдельным и отличным от CS_DROPSHADOW, и работает только , когда включен Aero. Невозможно отключить и выключить отдельные окна. Более того, поскольку тема Aero удалена из Windows 8, у нее никогда не будет этих теней.

+0

У него уже есть эта тень. Вывод DWM работает так же хорошо и в Winforms, используя OnHandleCreated. Все это выглядит очень плохой в Win8. –

+0

хорошо, как @HansPassant, и снова cp дает такую ​​же тень, как и вторая картинка –

7

Humm ,,, Просто мимо кода, и вы получите окна 7 Drop Shadow как это >>>http://marcin.floryan.pl/wp-content/uploads/2010/08/WPF-Window-native-shadow.png

Imports System.Runtime.InteropServices 

Public Class IMSS_SplashScreen 
    Private aeroEnabled As Boolean 
    Protected Overrides ReadOnly Property CreateParams() As CreateParams 
     Get 
      CheckAeroEnabled() 
      Dim cp As CreateParams = MyBase.CreateParams 
      If Not aeroEnabled Then 
       cp.ClassStyle = cp.ClassStyle Or NativeConstants.CS_DROPSHADOW 
       Return cp 
      Else 
       Return cp 
      End If 
     End Get 
    End Property 
    Protected Overrides Sub WndProc(ByRef m As Message) 
     Select Case m.Msg 
      Case NativeConstants.WM_NCPAINT 
       Dim val = 2 
       If aeroEnabled Then 
        NativeMethods.DwmSetWindowAttribute(Handle, 2, val, 4) 
        Dim bla As New NativeStructs.MARGINS() 
        With bla 
         .bottomHeight = 1 
         .leftWidth = 1 
         .rightWidth = 1 
         .topHeight = 1 
        End With 
        NativeMethods.DwmExtendFrameIntoClientArea(Handle, bla) 
       End If 
       Exit Select 
     End Select 
     MyBase.WndProc(m) 
    End Sub 
    Private Sub CheckAeroEnabled() 
     If Environment.OSVersion.Version.Major >= 6 Then 
      Dim enabled As Integer = 0 
      Dim response As Integer = NativeMethods.DwmIsCompositionEnabled(enabled) 
      aeroEnabled = (enabled = 1) 
     Else 
      aeroEnabled = False 
     End If 
    End Sub 
End Class 
Public Class NativeStructs 
    Public Structure MARGINS 
     Public leftWidth As Integer 
     Public rightWidth As Integer 
     Public topHeight As Integer 
     Public bottomHeight As Integer 
    End Structure 
End Class 
Public Class NativeMethods 
    <DllImport("dwmapi")> _ 
    Public Shared Function DwmExtendFrameIntoClientArea(ByVal hWnd As IntPtr, ByRef pMarInset As NativeStructs.MARGINS) As Integer 
    End Function 
    <DllImport("dwmapi")> _ 
    Friend Shared Function DwmSetWindowAttribute(ByVal hwnd As IntPtr, ByVal attr As Integer, ByRef attrValue As Integer, ByVal attrSize As Integer) As Integer 
    End Function 
    <DllImport("dwmapi.dll")> _ 
    Public Shared Function DwmIsCompositionEnabled(ByRef pfEnabled As Integer) As Integer 
    End Function 
End Class 
Public Class NativeConstants 
    Public Const CS_DROPSHADOW As Integer = &H20000 
    Public Const WM_NCPAINT As Integer = &H85 
End Class 
+0

Отличная реализация, но, похоже, она теряет тень, когда управление теряет/получает фокус или взаимодействует с другими окнами. Вы знаете, как это решить? – series0ne

+0

@seriesOne звучит так, как будто вам просто нужно обработать событие изменения размера и вызвать this.Update() или this.Refresh(). поэтому окно «вынуждено» перекрашивать себя, таким образом, также перекраивая тень. Я еще не пробовал этот код, но я предполагаю, что именно поэтому. – SE13013

11

Вот мой C# реализация. Это похоже на Al.Pertro's, но вы заметите, что когда вы теряете фокус и восстанавливаете фокус, тень репрессирует себя.

Я также добавил к коду, чтобы можно было перетаскивать мышью.

public partial class Form1 : Form 
{ 
    [DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")] 
    private static extern IntPtr CreateRoundRectRgn 
    (
     int nLeftRect, // x-coordinate of upper-left corner 
     int nTopRect, // y-coordinate of upper-left corner 
     int nRightRect, // x-coordinate of lower-right corner 
     int nBottomRect, // y-coordinate of lower-right corner 
     int nWidthEllipse, // height of ellipse 
     int nHeightEllipse // width of ellipse 
    );   

    [DllImport("dwmapi.dll")] 
    public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset); 

    [DllImport("dwmapi.dll")] 
    public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize); 

    [DllImport("dwmapi.dll")] 
    public static extern int DwmIsCompositionEnabled(ref int pfEnabled); 

    private bool m_aeroEnabled;      // variables for box shadow 
    private const int CS_DROPSHADOW = 0x00020000; 
    private const int WM_NCPAINT = 0x0085; 
    private const int WM_ACTIVATEAPP = 0x001C; 

    public struct MARGINS       // struct for box shadow 
    { 
     public int leftWidth; 
     public int rightWidth; 
     public int topHeight; 
     public int bottomHeight; 
    } 

    private const int WM_NCHITTEST = 0x84;   // variables for dragging the form 
    private const int HTCLIENT = 0x1; 
    private const int HTCAPTION = 0x2; 

    protected override CreateParams CreateParams 
    { 
     get 
     { 
      m_aeroEnabled = CheckAeroEnabled(); 

      CreateParams cp = base.CreateParams; 
      if (!m_aeroEnabled) 
       cp.ClassStyle |= CS_DROPSHADOW; 

      return cp; 
     } 
    } 

    private bool CheckAeroEnabled() 
    { 
     if (Environment.OSVersion.Version.Major >= 6) 
     { 
      int enabled = 0; 
      DwmIsCompositionEnabled(ref enabled); 
      return (enabled == 1) ? true : false; 
     } 
     return false; 
    } 

    protected override void WndProc(ref Message m) 
    { 
     switch (m.Msg) 
     { 
      case WM_NCPAINT:      // box shadow 
       if (m_aeroEnabled) 
       { 
        var v = 2; 
        DwmSetWindowAttribute(this.Handle, 2, ref v, 4); 
        MARGINS margins = new MARGINS() 
        { 
         bottomHeight = 1, 
         leftWidth = 1, 
         rightWidth = 1, 
         topHeight = 1 
        }; 
        DwmExtendFrameIntoClientArea(this.Handle, ref margins); 

       } 
       break; 
      default: 
       break; 
     } 
     base.WndProc(ref m); 

     if (m.Msg == WM_NCHITTEST && (int)m.Result == HTCLIENT)  // drag the form 
      m.Result = (IntPtr)HTCAPTION; 

    } 

    public Form1() 
    { 
     m_aeroEnabled = false; 

     this.FormBorderStyle = FormBorderStyle.None; 

     InitializeComponent(); 
    } 
} 
+0

Примечание. если вы установите структуру MARGINS на -1 на всех ребрах и вызовите CreateRoundRectRgn из вашего метода OnSizeChanged, вы также можете получить закругленные края, но это заставляет тень исчезнуть, когда форма теряет фокус ... любые идеи? – series0ne