2012-01-09 7 views
9

versión corta:de Windows Dropshadow 7 estilo en forma sin bordes

Objetivo: A, oscuro, Windows 7 dropshadow profundamente en WinForm sin bordes en C#


Soluciones existentes conocidas 1: Sencilla sombra de estilo XP usando CreateParams.

Problema: A débil, a la luz, a feo.


soluciones existentes conocidos 2: Reemplazar GDI de forma con mapa de bits.

Problema: Pierde la capacidad de usar controles, solo funciona como pantalla de bienvenida.


objetivo de este post: encontrar una solución a este problema mediana o un todos juntos mejor.

. . .

Versión larga:

(Editar:. Me refiero a la sombra base que va a lo largo de la frontera de cualquier forma de ventanas, si eso no era clara) entiendo que hay una manera de hacer DropShadows estilo XP en C# usando:

código C# 1 - simple de estilo XP dropshadow (Problema: a la luz, al débil, al feo)

// Define the CS_DROPSHADOW constant 
private const int CS_DROPSHADOW = 0x00020000; 

// Override the CreateParams property 
protected override CreateParams CreateParams 
{ 
    get 
    { 
     CreateParams cp = base.CreateParams; 
     cp.ClassStyle |= CS_DROPSHADOW; 
     return cp; 
    } 
} 

Sin embargo, estoy tratando de descubrir cómo hacer que se vean como el hacer en Windows 7 (sombras más grandes y más grandes) y no puedo encontrar la mejor manera de hacerlo.

tengo un método crea ahora que me permita invalidar todo el formulario de GDI y aparecen como una pantalla de bienvenida haría (crédito no la mía):

código C# 2: Reemplazar forma GDI con el mapa de bits (Problema: ¿ 't utilizar los controles de formulario, difícil de mantener GUI)

public void SetBitmap(Bitmap bitmap, byte opacity) 
    { 
     if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) 
      throw new ApplicationException("The bitmap must be 32ppp with alpha-channel."); 

     // 1. Create a compatible DC with screen; 
     // 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC; 
     // 3. Call the UpdateLayeredWindow. 

     IntPtr screenDc = Win32.GetDC(IntPtr.Zero); 
     IntPtr memDc = Win32.CreateCompatibleDC(screenDc); 
     IntPtr hBitmap = IntPtr.Zero; 
     IntPtr oldBitmap = IntPtr.Zero; 

     try 
     { 
      hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap 
      oldBitmap = Win32.SelectObject(memDc, hBitmap); 

      Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height); 
      Win32.Point pointSource = new Win32.Point(0, 0); 
      Win32.Point topPos = new Win32.Point(Left, Top); 
      Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION(); 
      blend.BlendOp = Win32.AC_SRC_OVER; 
      blend.BlendFlags = 0; 
      blend.SourceConstantAlpha = opacity; 
      blend.AlphaFormat = Win32.AC_SRC_ALPHA; 

      Win32.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA); 
     } 
     finally 
     { 
      Win32.ReleaseDC(IntPtr.Zero, screenDc); 
      if (hBitmap != IntPtr.Zero) 
      { 
       Win32.SelectObject(memDc, oldBitmap); 
       Win32.DeleteObject(hBitmap); 
      } 
      Win32.DeleteDC(memDc); 
     } 
    } 


    protected override CreateParams CreateParams 
    { 
     get 
     { 
      CreateParams cp = base.CreateParams; 
      cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style 
      return cp; 
     } 
    } 

sin embargo, esto me da un fondo completo de 32 bits (como yo requiero para añadir el dropshadow manualmente), pero pierden la capacidad de crear la forma elementos que son visibles.

Básicamente, estoy tratando de encontrar una mediana entre estos dos métodos. Algo que me dará sombras profundas y oscuras sin perder otras funcionalidades/causando requisitos excesivos de repintado.

+1

¿Cuál es exactamente tu pregunta? Realmente este no es el lugar para obtener la solución escrita para usted. –

+3

@Ramhound La pregunta es simple. Estoy buscando apuntar en la dirección correcta en esto. Mi pregunta está bien investigada y tan clara como pude. Solo quiero saber si alguien sabe de una mejor manera de crear una sombra de gotas estilo Windows 7. – Corylulu

+1

¿Puedes agregar una captura de pantalla o una maqueta del resultado deseado? –

Respuesta

7

Bien, entonces después de aproximadamente 4 horas de lluvia de ideas y codificación, finalmente he desarrollado una solución. Básicamente, hice 2 formas.

Forma # 1: Crear el dropshadow modificando y combinando 8 imágenes (4 esquinas gradientes + 4 gradientes lineales para cada dirección) y definirlas como un fondo con el segundo código que he publicado anteriormente (código C# 2: Reemplace el formulario GDI con Bitmap). El código lo explica bastante.

public partial class Dropshadow : Form 
{ 

    public Dropshadow(Form parentForm) 
    { 
     /*This bit of code makes the form click-through. 
      So you can click forms that are below it in z-space */ 
     int wl = GetWindowLong(this.Handle, -20); 
     wl = wl | 0x80000 | 0x20; 
     SetWindowLong(this.Handle, -20, wl); 

     InitializeComponent(); 

     //Makes the start location the same as parent. 
     this.StartPosition = parentForm.StartPosition; 

     parentForm.Activated += ParentForm_Activated; //Fires on parent activation to do a this.BringToFront() 
     this.Deactivate += This_Deactivated; //Toggles a boolean that ensures that ParentForm_Activated does fire when clicking through (this) 
     parentForm.Closed += ParentForm_Closed; //Closes this when parent closes 
     parentForm.Move += ParentForm_Move; //Follows movement of parent form 

     //Draws border with standard bitmap modifications and merging 
     /* Omitted function to avoid extra confusion */ 
     Bitmap getShadow = DrawBlurBorder(parentForm.ClientSize.Width, parentForm.ClientSize.Height); 
     /* **This code was featured in the original post:** */ 
     SetBitmap(getShadow, 255); //Sets background as 32-bit image with full alpha. 

     this.Location = Offset; //Set within DrawBlurBorder creates an offset 

    } 
    private void ParentForm_Activated(object o, EventArgs e) 
    { 
     /* Sets this form on top when parent form is activated.*/ 
     if (isBringingToFront) 
     { 
      /*Hopefully prevents recusion*/ 
      isBringingToFront = false; 
      return; 
     } 

     this.BringToFront(); 


     /* Some special tweaks omitted to avoid confusion */ 
    } 
    private void This_Deactivated(object o, EventArgs e) 
    { 
     /* Prevents recusion. */ 
     isBringingToFront = true; 
    } 
    /* Closes this when parent form closes. */ 
    private void ParentForm_Closed(object o, EventArgs e) 
    { 
     this.Close(); 
    } 
    /* Adjust position when parent moves. */ 
    private void ParentForm_Move(object o, EventArgs e) 
    { 
     if(o is Form) 
      this.Location = new Point((o as Form).Location.X + Offset.X, (o as Form).Location.Y + Offset.Y); 
    } 
} 

Forma # 2: Esto sólo inicia el formulario dropshadow en el lanzamiento y también creó algunas interfaces para permitir una mayor integración y flexibilidad que he omitido para evitar la confusión adicional. Básicamente, los métodos para garantizar que el formulario Dropshadow no eliminara los clics del mouse del formulario activo y no obligaría al usuario a tener que hacer clic dos veces en un botón si el formulario Dropshadow estaba en la parte superior.

+1

No sé si esta es la mejor manera de hacerlo, pero creo que es bastante inteligente. –

3

Gracias, Corylulu.

Una clase funcional es here.

var f = new Dropshadow(this) 
{ 
    BorderRadius = 40, 
    ShadowColor = Color.Blue 
}; 

f.RefreshShadow(); 

DEMO

El DrawShadow crear una sombra como mapa de bits, pero no es perfecto todavía. Esta clase no es perfecta, pero funciona.

Por cierto, no sé cómo ocultar el formulario oculto en la barra de tareas. Establecer ShowInTaskBar = false hará que el formulario desaparezca.

EDITAR

vuelvo a escribir la clase, ahora parece que esto, un DropShadow real.

Fuente es here.

Una cosa que debes saber es que esta clase no considera el border-radius (toma forma css).

propiedad principal es

  • ShadowColor
  • ShadowV
  • ShadowH
  • ShadowSpread
  • shadowBlur

La propiedad es la misma que css box-shadow, ver here

Estos propertyies

  • ShadowSpread
  • shadowBlur
  • ShadowColor

que requieren llamada manual RefreshShadow().

Ve a la demo project

+0

Eso es interesante sobre el problema de ShowInTaskbar. No parece tener el mismo problema. Destruiré el código que tengo y lo enviaré si lo desea. Sin embargo, es un código muy antiguo, por lo que no está exactamente optimizado. – Corylulu

+0

Mi versión se complica un poco más y olvido exactamente por qué: P, pero aquí están todas las cosas que hice para que el código funcionara bien. Algo de eso podría ser específico de lo que estaba tratando de hacer, pero en su mayoría traté de sacar todo eso. http://pastie.org/8588447 – Corylulu

+0

Creo un nuevo proyecto para probar la sombra de gotas, descubro que 'ShowInTaskBar' está bien. Ahora, la parte difícil es dibujar un mapa de bits en la sombra. Me gustaría usar el parámetro descrito [aquí] (http://www.w3schools.com/cssref/css3_pr_box-shadow.asp). Me di cuenta de que dibujas la sombra usa la imagen, que no es modificable – wener