Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea รจ quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

Ereditare da PrintDocument e decorare la nuova classe con un custom Attribute

Devo confessarlo, anche io sono rimasto un po' perplesso dopo l'esempio di Andrea nell'ultimo Workshop di UGIdotNET dell'altro ieri. Se ricordo bene, lui aveva creato Attribute [MinLength], [MaxLength] e così via, per decorare la sua classe e aggiungendo attributi di validazione riutilizzabili. E' due giorni che penso a come sfruttare meglio gli Attribute di .NET e ieri sera, poco prima di uscire con gli amici, ecco la rivelazione che mi è venuta dall'alto.

Nel mio ultimo post [MCAD], ho parlato di come utilizzare la classe PrintDocument per implementare all'interno della nostra applicazione funzioni di stampa. Usando le funzioni GDI+, e gestendo l'evento PrintPage, bisogna tutte le volte disegnare testo (DrawString) e grafica (DrawLine, DrawCurve e quant'altro). La trovo una cosa piuttosto noiosa: pensiamoci bene. Se sto creando la classica applicazione di fatturazione, devo creare il classico report per stampare fatture, documenti di trasporto, ordini clienti e fornitori e così via. Se continuiamo a pensarci su, vediamo come su ogni report di stampa bisogna comunque mettere il logo dell'azienda da qualche parte. Perchè fare tutte le volte l'impaginazione quando posso velocizzare il lavoro? Ecco la soluzione che ho messo in piedi questa mattina.

Ho creato una nuova classe AdvancedPrintDocument, che eredita dalla classe base PrintDocument. Il codice completo è il seguente:

using System;
using System.Drawing;
using Libba;

namespace Libba
{
    [Logo("K:\\Documenti\\Immagini\\Personali Igor\\blog_igor.jpg", 70, 200)]
    
public class AdvancedPrintDocument : System.Drawing.Printing.PrintDocument
    {
        
public AdvancedPrintDocument()
        {
            
//
            // TODO: aggiungere qui la logica del costruttore
            //
        
}

        
protected override void OnPrintPage(System.Drawing.Printing.PrintPageEventArgs e)
        {
            
base.OnPrintPage (e);
        
            
float posy = e.MarginBounds.Top, posx = e.MarginBounds.Left;
            Attribute[] attr = Attribute.GetCustomAttributes(
typeof(AdvancedPrintDocument));

            
foreach (Attribute a in attr)
            {
                
if (a is Libba.Logo)
                {
                    Logo lg = (Logo) a;
                    Image logo = Image.FromFile(lg.BitmapFileName, 
true);
                    
                    
#region "Calcolo delle coordinate"
                    if 
(lg.Coordinata.X == 0)
                    {
                        
switch (lg.ImageAlign)
                        {
                            
case ContentAlignment.BottomCenter:
                            {
                                posx = (e.PageBounds.Width - logo.PhysicalDimension.Width) / 2;
                                posy = e.MarginBounds.Bottom - logo.PhysicalDimension.Height;
                                
break;
                            }
                            
case ContentAlignment.BottomLeft:
                            {
                                posx = e.MarginBounds.Left;
                                posy = e.MarginBounds.Bottom - logo.PhysicalDimension.Height;
                                
break;
                            }
                            
case ContentAlignment.BottomRight:
                            {
                                posx = e.MarginBounds.Right - logo.PhysicalDimension.Width;
                                posy = e.MarginBounds.Bottom - logo.PhysicalDimension.Height;
                                
break;
                            }
                            
case ContentAlignment.MiddleCenter:
                            {
                                posx = (e.PageBounds.Width - logo.PhysicalDimension.Width) / 2;
                                posy = (e.PageBounds.Height - logo.PhysicalDimension.Height) / 2;
                                
break;
                            }
                            
case ContentAlignment.MiddleLeft:
                            {
                                posx = e.PageBounds.Left;
                                posy = (e.PageBounds.Height - logo.PhysicalDimension.Height) / 2;
                                
break;
                            }
                            
case ContentAlignment.MiddleRight:
                            {
                                posx = e.MarginBounds.Right - logo.PhysicalDimension.Width;
                                posy = (e.PageBounds.Height - logo.PhysicalDimension.Height) / 2;
                                
break;
                            }
                            
case ContentAlignment.TopLeft:
                            {
                                posx = e.MarginBounds.Left;
                                posy = e.MarginBounds.Top;
                                
break;
                            }
                            
case ContentAlignment.TopCenter:
                            {
                                posx = (e.PageBounds.Width - logo.PhysicalDimension.Width) / 2;
                                posy = e.MarginBounds.Top;
                                
break;
                            }
                            
case ContentAlignment.TopRight:
                            {
                                posx = e.MarginBounds.Right - logo.PhysicalDimension.Width;
                                posy = e.MarginBounds.Top;
                                
break;
                            }
                        }
                    }
                    
else
                    
{
                        posx = lg.Coordinata.X;
                        posy = lg.Coordinata.Y;
                    }
                    
#endregion

                    
// disegno la bitmap sull'oggetto Graphics posizionandolo come voluto
                    
e.Graphics.DrawImage(logo, posx, posy, logo.PhysicalDimension.Width, logo.PhysicalDimension.Height);
                }
            }
        }

    }
}

Non perdetevi troppo nell'implementazione. La cosa interessante che ho creato è l'attributo Logo, che in pratica è una classe il cui costruttore è stato overloadato 3 volte. Ecco il codice.

using System.Drawing;

namespace Libba
{
    
/// 
    /// Descrizione di riepilogo per Logo.
    
/// 


    
public class Logo : System.Attribute
    {

        
string bitmapFileName = string.Empty;
        ContentAlignment imageAlign;
        Point coordinata;

        
public string BitmapFileName
        {
            
get
            
{
                
return(this.bitmapFileName);
            }
            
set
            
{
                
this.bitmapFileName = value;
            }

        }


        
public ContentAlignment ImageAlign
        {
            
get
            
{
                
return(this.imageAlign);
            }
            
set
            
{
                
this.imageAlign = value;        
            }
        }


        
public Point Coordinata
        {
            
get
            
{
                
return(this.coordinata);
            }
            
set
            
{
                
this.coordinata = value;
            }
        }


        
public Logo(string BitmapFileName)
        {
            
this.bitmapFileName = BitmapFileName;
            
this.imageAlign = ContentAlignment.TopLeft;
        }

        
public Logo(string BitmapFileName, ContentAlignment ImageAlign)
        {
            
this.bitmapFileName = BitmapFileName;
            
this.imageAlign = ImageAlign;
        }

        
public Logo(string BitmapFileName, int X, int Y)
        {
            
this.bitmapFileName = BitmapFileName;
            
this.coordinata = new Point(X, Y);
        }
    }
}

Notate che la classe Logo eredita da System.Attribute. In breve le proprietà sono: bitmapFileName è una stringa contenente il percorso di un file bitmap sul nostro hard-disk. imageAlign è un valore dall'enum ContentAlignment che contiene l'allineamento che vogliamo dare alla nostra bitmap (TopLeft, TopRight e così via). Se non ci interessa dare un particolare allineamento, possiamo usare un oggetto coordinata per indicare la coordinata in alto a sinistra da cui vogliamo iniziare a disegnare la nostra bitmap. Il costruttore è stato ridefinito 3 volte:

  1. public Logo(string BitmapFileName)
  2. public Logo(string BitmapFileName, ContentAlignment ImageAlign)
  3. public Logo(string BitmapFileName, int X, int Y)

Nell'esempio sopra quindi, la nostra classe AdvancedPrintDocument è stata decorata con l'attributo Logo, passando il path dell'immagine e le coordinate (70, 200). Nell'overloading dell'evento OnPrintPage uso il metodo GetCustomAttributes per vedere se e come è stato utilizzato l'attributo custom Logo in questo caso, ovvero:

Attribute[] attr = Attribute.GetCustomAttributes(typeof(AdvancedPrintDocument));

foreach (Attribute a in attr)
{
    
if (a is Libba.Logo)
    {
        Logo lg = (Logo) a;
        Image logo = Image.FromFile(lg.BitmapFileName, 
true);
        
        
//calcolo delle coordinate

        // disegno la bitmap sull'oggetto Graphics posizionandolo come voluto
        
e.Graphics.DrawImage(logo, posx, posy, logo.PhysicalDimension.Width, logo.PhysicalDimension.Height);
    }
}

Se il metodo GetCustomAttributes mi ritorna un Attribute di tipo Libba.Logo (che è la mia classe che eredita da System.Attribute), allora prelevo l'attribute facendo il casting al tipo Logo. Calcolo le coordinate (nel codice sopra ho riportato solo il commento) facendo uno switch sui possibili valori di imageAlign, oppure  Alla fine disegno semplicemente sull'oggetto Graphics la bitmap che ho caricato da file, allineandola o posizionandola come indicato nei valori dell'attributo.

Questo che ho descritto credo sia un buon utilizzo di Custom Attribute: è sufficiente usare la nuova classe AdvancedPrintDocument per avere tutte le features offerte dalla classe base: in più, usando l'Attribute Logo possiamo impaginare un'immagine molto velocemente, posizionandola o centrandola dove vogliamo e senza troppe complicazioni. Che ne dite?

powered by IMHO 1.2

Print | posted on sabato 16 luglio 2005 13:53 |

Feedback

Gravatar

# Re: Ereditare da PrintDocument e decorare la nuova classe con un custom Attribute

E bravo Igor...
16/07/2005 15:07 | Marco Santoni
Gravatar

# re: Ereditare da PrintDocument e decorare la nuova classe con un custom Attribute

Attributi rulez!!!
19/07/2005 14:37 | Simone Chiaretta
Gravatar

# [MCAD.14] Completare la stampa con una bella anteprima

19/07/2005 15:05 | Technology Experience
Gravatar

# [MCAD.15] PageSetupDialog e PrintDialog, pi

21/07/2005 15:18 | Technology Experience
Gravatar

# re: Ereditare da PrintDocument e decorare la nuova classe con un custom Attribute

Fico :)
Complimenti!
13/09/2005 19:43 | Diego
Gravatar

# [OT] Non c'

10/10/2005 19:56 | Technology Experience
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET