2012-01-09 15 views
9

Versione corta:di Windows Dropshadow 7 stile in forma senza bordi

Obiettivo: Un profondo, scuro, Windows 7 dropshadow in WinForm senza bordi in C#


Soluzioni esistenti note 1: Semplice ombretto in stile XP con CreateParams.

Problema: Da debole, da leggero a brutto.


noti soluzioni esistenti 2: Riposizionare GDI della forma con bitmap.

Problema: Perdi la possibilità di utilizzare i controlli, solo funzionali come una schermata iniziale.


Obiettivo per questo post: trovare una soluzione mediana a questo problema o un insieme migliore.

. . .

Long Version:

(Edit:. Mi riferisco al drop-ombra in corso lungo il confine di ogni forma finestre, se non fosse chiaro) ho capito che ci sia un modo per rendere XP dropshadows stile in C# utilizzando:

codice C# 1 - semplice XP-style dropshadow (Problema: alla luce, ai deboli, a brutto)

// 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; 
    } 
} 

Tuttavia, sto cercando di capire come farle apparire come fanno in Windows 7 (ombre più profonde e più grandi) e non riesco a capire il modo migliore per farlo.

Ho un metodo ormai creato che mi permetta a ignorare tutto il GDI forma e apparire come una schermata iniziale sarebbe (credito non mia):

C# Codice 2: Sostituire modulo GDI con Bitmap (Problema: è possibile 't utilizzare i controlli dei moduli, difficile da mantenere 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; 
     } 
    } 

Tuttavia, questo mi dà uno sfondo pieno a 32-bit (come ho bisogno di aggiungere il dropshadow manualmente), ma perde la capacità di creare la forma elementi che sono visibili.

Quindi, in sostanza, sto cercando di capire una mediana tra questi due metodi. Qualcosa che mi darà ombre scure profonde e scure senza perdere altre funzionalità/causando eccessivi requisiti di riverniciatura.

+1

Che cosa è esattamente la tua domanda? Questo non è il posto giusto per ottenere la soluzione scritta per te. –

+3

@Ramhound La domanda è semplice. Sto cercando di essere indicato nella giusta direzione su questo. La mia domanda è ben studiata e chiara come potrei farcela. Voglio solo sapere se qualcuno conosce un modo migliore per creare un ombretto in stile Windows 7. – Corylulu

+1

Puoi aggiungere uno screenshot o un mockup del risultato desiderato? –

risposta

7

Ok, quindi dopo circa 4 ore di brainstorming e codifica, ho finalmente sviluppato una soluzione. Fondamentalmente, ho creato 2 forme.

Modulo # 1: Creare il dropshadow modificando e combinando 8 immagini (4 angoli gradienti + 4 gradienti lineari per ogni direzione) e impostarle come sfondo utilizzando il secondo codice che ho postato sopra (codice C# 2: Sostituire il modulo GDI con Bitmap). Il codice praticamente lo spiega.

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

Modulo # 2: Questo lancia solo la forma dropshadow al momento del lancio e ho anche creato alcune interfacce per consentire una maggiore integrazione e flessibilità che ho omesso per evitare confusione in più. Fondamentalmente i metodi per garantire che la forma di Dropshadow non stia portando via i clic del mouse dal modulo attivo e non costringerebbe l'utente a fare clic su un pulsante due volte se la forma di Dropshadow era in cima.

+1

Non so se questo è il modo migliore per farlo, ma penso che sia abbastanza intelligente. –

3

Grazie, Corylulu.

Una classe lavorabile è here.

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

f.RefreshShadow(); 

DEMO

Il DrawShadow creare un'ombra come bitmap, ma non ancora perfetto. Questa classe non è perfetta, ma funziona.

BTW, non so come nascondere il modulo shadow nella barra delle applicazioni. Set ShowInTaskBar = false farà scomparire il modulo.

EDIT

riscrivo la classe, ora sembra che questo, un vero e proprio DropShadow.

Source è here.

Una cosa che dovresti sapere è questa classe non considerare il border-radius (prende forma css).

proprietà principale è

  • ShadowColor
  • ShadowV
  • ShadowH
  • ShadowSpread
  • ShadowBlur

La proprietà è la stessa CSS box-shadow, vedere here

Questi propertyies

  • ShadowSpread
  • ShadowBlur
  • ShadowColor

richiedono chiamata manuale RefreshShadow().

Vai demo project

+0

Questo è interessante per il problema ShowInTaskbar. Non ho lo stesso problema. Sviterei il codice che ho e lo spedirò se lo desideri. È un codice molto vecchio, quindi non è esattamente ottimizzato. – Corylulu

+0

La mia versione è un po 'più coinvolgente e ho dimenticato esattamente il motivo: P ma ecco tutte le cose che ho fatto per far funzionare bene il codice. Alcuni potrebbero essere specifici per quello che stavo tentando di fare, ma ho cercato soprattutto di prendere tutto questo. http://pastie.org/8588447 – Corylulu

+0

Creo un nuovo progetto per testare il dropshadow, scoprire che il 'ShowInTaskBar' va bene. Ora, la parte difficile è disegnare una bitmap shadow. Mi piacerebbe usare il parametro descritto [qui] (http://www.w3schools.com/cssref/css3_pr_box-shadow.asp). Ho notato che si disegna l'ombra usa l'immagine, che non è modificabile. – wener