2013-03-19 14 views
6

Sto provando a creare una classe derivata Control che supporta una proprietà Opcacity.
Questo controllo potrebbe ospitare sia il testo e l'immagine e si beable a svanire fuori e in
Ecco il mio codice:.Controllo di dissolvenza in C#

internal class FadeControl : Control 
{ 
    private int opacity = 100; 

    public FadeControl() 
    { 
     SetStyle(ControlStyles.SupportsTransparentBackColor, true); 
    } 

    public int Opacity 
    { 
     get 
     { 
      return opacity; 
     } 
     set 
     { 
      if (value > 100) opacity = 100; 
      else if (value < 1) opacity = 1; 
      else opacity = value; 

      if (Parent != null) 
       Parent.Invalidate(Bounds, true); 
     } 
    } 

    protected override CreateParams CreateParams 
    { 
     get 
     { 
      CreateParams cp = base.CreateParams; 
      cp.ExStyle = cp.ExStyle | 0x20; 
      return cp; 
     } 
    } 

    protected override void OnPaintBackground(PaintEventArgs e) 
    { 
     //do nothing 
    } 

    protected override void OnMove(EventArgs e) 
    { 
     RecreateHandle(); 
    } 

    protected override void OnPaint(PaintEventArgs e) 
    { 
     using (Graphics g = e.Graphics) 
     { 
      Rectangle bounds = new Rectangle(0, 0, Width - 1, Height - 1); 
      int alpha = (opacity * 255)/100; 

      using (Brush bckColor = new SolidBrush(Color.FromArgb(alpha, BackColor))) 
      { 
       if (BackColor != Color.Transparent) 
        g.FillRectangle(bckColor, bounds); 
      } 

      ColorMatrix colorMatrix = new ColorMatrix(); 
      colorMatrix.Matrix33 = (float)alpha/255; 
      ImageAttributes imageAttr = new ImageAttributes(); 
      imageAttr.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 

      if (BackgroundImage != null) 
       g.DrawImage(BackgroundImage, bounds, 0, 0, Width, Height, GraphicsUnit.Pixel, imageAttr); 

      if (Text != string.Empty) 
      { 
       using (Brush txtBrush = new SolidBrush(Color.FromArgb(alpha, ForeColor))) 
       { 
        g.DrawString(Text, Font, txtBrush, 5, 5); 
       } 
      } 
     } 
    } 

    protected override void OnBackColorChanged(EventArgs e) 
    { 
     if (Parent != null) 
      Parent.Invalidate(Bounds, true); 

     base.OnBackColorChanged(e); 
    } 

    protected override void OnParentBackColorChanged(EventArgs e) 
    { 
     Invalidate(); 

     base.OnParentBackColorChanged(e); 
    } 
} 

ho putted il controllo di una maschera che ha un timer su di esso.
Il timer imposta l'opacità del controllo da 0 a 100 e viceversa e funziona correttamente.
Il problema che sto cercando di risolvere è che il controllo sfarfallio mentre si modifica la sua opacità.
L'impostazione del controllo su ControlStyles.DoubleBuffer renderà il controllo invisibile sul modulo.

Qualsiasi consiglio sarà benvenuto.

+3

Ciò è inevitabile quando si utilizza WS_EX_TRANSPARENT. Quindi non usarlo. –

+0

possibile duplicato di [Fade a panel- Windows forms] (http://stackoverflow.com/questions/10178559/fade-a-panel-windows-forms) –

+0

Il controllo sul collegamento non supporta il backcolor trasparente. Vorrei che il cotrol fosse in grado di sfumare in entrata e in uscita mentre conteneva immagini e testi PNG. – toy4fun

risposta

0

Non è stato possibile utilizzare sia un doppio buffer che WS_EX_TRANSPARENT (0x20) per lo sfondo trasparente. Così ho deciso di implementare lo sfondo trasparente copiando il contenuto del controllo genitore e utilizzando il doppio buffer per evitare lo sfarfallio.

Il seguente è il codice finale di origine, testato e di lavoro:

using System; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Windows.Forms; 

internal class FadeControl : Control 
{ 
    private int opacity = 100; 
    private Bitmap backgroundBuffer; 
    private bool skipPaint; 

    public FadeControl() 
    { 
     SetStyle(ControlStyles.SupportsTransparentBackColor, true); 
     SetStyle(ControlStyles.ResizeRedraw, true); 
     SetStyle(ControlStyles.DoubleBuffer | 
       ControlStyles.AllPaintingInWmPaint | 
       ControlStyles.UserPaint, true); 
    } 

    public int Opacity 
    { 
     get 
     { 
      return opacity; 
     } 
     set 
     { 
      if (value > 100) opacity = 100; 
      else if (value < 1) opacity = 1; 
      else opacity = value; 

      if (Parent != null) 
       Parent.Invalidate(Bounds, true); 
     } 
    } 

    protected override void OnPaintBackground(PaintEventArgs e) 
    { 
     //do nothig 
    } 

    protected override void OnMove(EventArgs e) 
    { 
     RecreateHandle(); 
    } 

    private void CreateBackgroundBuffer(Control parent) 
    { 
     int offsetX; 
     int offsetY; 
     GetOffsets(out offsetX, out offsetY, parent); 
     backgroundBuffer = new Bitmap(Width + offsetX, Height + offsetY); 
    } 

    protected override void OnResize(EventArgs e) 
    { 
     var parent = Parent; 
     if (parent != null) 
     { 
      CreateBackgroundBuffer(parent); 
     } 
     base.OnResize(e); 
    } 

    private void GetOffsets(out int offsetX, out int offsetY, Control parent) 
    { 
     var parentPosition = parent.PointToScreen(Point.Empty); 
     offsetY = Top + parentPosition.Y - parent.Top; 
     offsetX = Left + parentPosition.X - parent.Left; 
    } 

    private void UpdateBackgroundBuffer(int offsetX, int offsetY, Control parent) 
    { 
     if (backgroundBuffer == null) 
     { 
      CreateBackgroundBuffer(parent); 
     } 
     Rectangle parentBounds = new Rectangle(0, 0, Width + offsetX, Height + offsetY); 
     skipPaint = true; 
     parent.DrawToBitmap(backgroundBuffer, parentBounds); 
     skipPaint = false; 
    } 

    private void DrawBackground(Graphics graphics, Rectangle bounds) 
    { 
     int offsetX; 
     int offsetY; 
     var parent = Parent; 
     GetOffsets(out offsetX, out offsetY, parent); 
     UpdateBackgroundBuffer(offsetX, offsetY, parent); 
     graphics.DrawImage(backgroundBuffer, bounds, offsetX, offsetY, Width, Height, GraphicsUnit.Pixel); 
    } 

    private void Draw(Graphics graphics) 
    { 
     Rectangle bounds = new Rectangle(0, 0, Width, Height); 
     DrawBackground(graphics, bounds); 

     int alpha = (opacity * 255)/100; 

     using (Brush bckColor = new SolidBrush(Color.FromArgb(alpha, BackColor))) 
     { 
      if (BackColor != Color.Transparent) 
      { 
       graphics.FillRectangle(bckColor, bounds); 
      } 
     } 

     ColorMatrix colorMatrix = new ColorMatrix(); 
     colorMatrix.Matrix33 = (float)alpha/255; 
     ImageAttributes imageAttr = new ImageAttributes(); 
     imageAttr.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 

     if (BackgroundImage != null) 
     { 
      graphics.DrawImage(BackgroundImage, bounds, 0, 0, Width, Height, GraphicsUnit.Pixel, imageAttr); 
     } 

     if (Text != string.Empty) 
     { 
      using (Brush txtBrush = new SolidBrush(Color.FromArgb(alpha, ForeColor))) 
      { 
       graphics.DrawString(Text, Font, txtBrush, 5, 5); 
      } 
     } 
    } 

    protected override void OnPaint(PaintEventArgs e) 
    { 
     if (!skipPaint) 
     { 
      Graphics graphics = e.Graphics; 
      Draw(graphics); 
     } 
    } 

    protected override void OnBackColorChanged(EventArgs e) 
    { 
     if (Parent != null) 
     { 
      Parent.Invalidate(Bounds, true); 
     } 
     base.OnBackColorChanged(e); 
    } 

    protected override void OnParentBackColorChanged(EventArgs e) 
    { 
     Invalidate(); 
     base.OnParentBackColorChanged(e); 
    } 
} 

Si noti che il metodo CreateParams non è più presente, anche ho cambiato il contructor.

Il campo skipPaint è sapere quando non dipingere per poter dire al genitore di disegnarsi su una bitmap durante OnPaint senza ricorrere alla ricorsione infinita.

backgroundBuffer non implementa il doppio buffering, ma per mantenere una copia del contenuto del genitore senza il rendering del controllo. Viene aggiornato ogni vernice, so che ci sono soluzioni più efficienti ... * tuttavia questo approccio lo mantiene semplice e non dovrebbe essere un collo di bottiglia a meno che non si abbiano troppi di questi controlli sullo stesso contenitore.

*: una soluzione migliore sarebbe aggiornarla ogni volta che il genitore invalida. Futhermore lo ha condiviso tra tutti i FadeControls nello stesso genitore.

+0

Appena avuto la possibilità di testarlo - funziona perfettamente. Grazie. – toy4fun

Problemi correlati