54 messaggi dal 13 settembre 2010
Ok !!
Sono riuscito a creare e ad impaginare i pdf, in effetti avevi ragione sui compromessi da adottare per far risultare qualcosa di decente.
E' stato abbastanza difficile configurare itextsharp (trovare la dll giusta in base al framework utilizzato, fare le giuste imports e utilizzare i comandi esatti per la creazione e la formattzione di tabelle) ma una volta capito il funzionamento devo ammettere che è uno strumento molto potente.

Ora mi trovo in questa situazione:
- ho la pagina commessadettaglio.aspx?id=xx in cui visualizzo il dettaglio della commessa passata in querystring (5 gridview e 1 detailsview)

- ho la pagina creapdf.aspx?id=xx in cui creo il pdf della commessa passata in querystring e salvo il file su server. Questa pagina ha body onload=window.close così si crea il pdf e si chiude la pagina

- ho una pagina commesse.aspx in cui ho 1 gridview con il riepilogo di tutte le commesse, qui posso
1) aprire commessa in dettaglio -> commessadettaglio.aspx?id=xx
2) spuntare i checkbox di ogni commessa per poi mandare in stampa cartacea tutte le commesse selezionate
3) spuntare i checkbox di ogni commessa per poi creare il pdf di tutte le commesse selezionate
Il pulsante pdf presente su questa pagina richiama una funzione che genera uno script lato client che apre 1 pagina creapdf.aspx?id=xx per ogni commessa selezionata tramite checkbox, ogni pagina crea il pdf delle commessa e poi si richiude subito.

Quest'ultima strategia non mi sembra molto corretta, sarebbe molto più elegante utilizzare la procedura da te descritta tramite repeater.
Procedura che poi riutilizzerei poi per la stampa cartacea (Ovviamente richiamando un'altra pagina, stampa.aspx).
Ma ad esser sincero non ho capito molto bene come implementare la tua idea, in particolare
- gli id della commesse chekkate li passo tutti tramite querystring divisi da virgola(tieni presente che potrebbero essere anche un centinaio)?
- una volta ricevuti gli id delle commesse come si comporta il repeater?
- è proprio necessario utilizzare un user control?

Thanks!
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,

gdalbell ha scritto:

- gli id della commesse chekkate li passo tutti tramite querystring divisi da virgola(tieni presente che potrebbero essere anche un centinaio)?

sì, in querystring puoi passare fino a 1-2 Kb di dati. Con un centinaio di valori non sarà molto bello a vedersi ma questo è il problema minore poiché in alternativa potresti anche usare una variabile di sessione. Il vero problema è che, se una sola pagina sarà incaricata di creare tutti e 100 i pdf, potrebbe pure andare in timeout e non riuscire a completare l'operazione. Questo dipende da quanto tempo ci mette a creare ciascun PDF. E non è comunque una bella cosa lasciare che l'utente resti in attesa per un tempo indeterminato.
A questo punto la tua soluzione è migliore perché, volendo, ti permette di far avanzare una barra di progresso che, mano mano, informa l'utente sulla percentuale di completamento.

Casomai valuta l'uso di iframe nascosti anziché popup che si aprono e chiudono davanti gli occhi dell'utente. Questa soluzione, comunque, ha anch'essa un suo difetto: impedisce all'utente di cambiare pagina e lo "blocca" nel suo lavoro.

Non sarebbe meglio se l'utente potesse avviare una procedura di lunga durata che va avanti indipendentemente dalla pagina in cui sta navigando?
Questo richiede un po' più di impegno per essere implementato.
Funziona così: gli id, anziché passarli via querystring o via Session, li inserisci in una tabella del database che puoi chiamare "coda_stampe" o "coda_esportazioni". Dopo aver fatto questo, invoca l'avvio di un servizio worker che, uno per uno, leggerà i record ed eseguirà il lavoro di stampa o di esportazione in PDF.

Il "servizio" può essere un servizio di windows, oppure un task di Asp.Net.

Se l'utente vuol sapere a che punto è arrivato il lavoro, dovrà visitare un'apposita pagina che recupererà gli ID presenti in coda_stampe o coda_esportazioni e che gli mostrerà quali sono stati lavorati dal servizio e quali no.

Ora, per la generazione dei PDF questo sistema può andar bene, ma è vero anche per la stampa? Se la tua è un'applicazione intranet, può darsi che i suoi utenti si trovino nella stanza affianco a quella del server e quindi avranno un facile accesso alla stampante usata dal server. Altrimenti dovrai ingegnarti in altri modi. C'è una discussione di pochi giorni fa sulla stampa da server.
http://forum.aspitalia.com/forum/post/389074/Mandare-Stampa-File-Lato-Server.aspx

gdalbell ha scritto:

- una volta ricevuti gli id delle commesse come si comporta il repeater?

Usa la lista di id come datasource per il repeater. Poi, all'interno del suo ItemTemplate usa l'id corrente per generare il dettaglio della commessa.

gdalbell ha scritto:

- è proprio necessario utilizzare un user control?

No, ma secondo me ti aiuterà a tenere la pagina pulita e leggibile. Inoltre potrai mantenere ben separati i compiti: lo user control penserà a generare il dettaglio di una commessa, mentre la pagina aspx si occuperà di disporle l'una sotto l'altra e in modo che siano stampate una per foglio.

ciao

Enjoy learning and just keep making
54 messaggi dal 13 settembre 2010
Perfetto!! Scrivo come ho fatto così potrebbe essere utile a qualcun'altro.

Alla fine ho fatto in modo che ad ogni checkbox flaggato vado a popolare una tabella del db inserendo gli id delle commesse scelte.

Poi in base al pulsante cliccato dall'utente vado a chiamare diverse pagine che fanno le seguenti operazioni:

- stampa.aspx: recupera gli id dalla tabella del db e (utilizzando il controllo utente "commessa" e un repeater) crea una dopo l'altra le commesse. In questo modo l'utente può stampare con un unico comando tutte le commesse precedentemente selezionate

- creapdf.aspx: recupera gli id dalla tabella del db e crea un pdf per ogni commessa scelta salvandolo direttamente nel server e aggiornando la tabella generale dei pdf. L'utente può avere il resoconto dei pdf creati e dei pdf che hanno generato errori potendo (in caso di errori) ritentare la creazione dei pdf che non sono stati eliminati dalla coda di stampa (cioè la tabella).

- stampapdf.aspx: recupera gli id dalla tabella del db e crea un pdf
unico (utilizzando itextsharp) in cui in ogni pagina c'è una commessa. Il pdf viene mandato in output così l'utente può aprirlo e mandarlo subito in stampa. Ho voluto sviluppare questa opzione in quanto potrebbe essere utile per l'utente voler stampare tutte le commesse senza vedere le intestazioni e i piè pagina che i browser aggiungono in automatico.

Per quanto riguarda il problema che avevi sollevato riguardo il timeout ho fatto varie prove e la creazione delle commesse in pdf è davvero veloce, 1 commessa è composta solo da testo (max 1 pagina) quindi il problema non dovrebbe proprio porsi.

Direi che la cosa è proprio completa e davvero devo ringraziarti alla grande! Senza i tuoi spunti e le tue spiegazioni non so se ce l'avrei fatta!

Ti chiedo solo un'ultima cosa in velocità:
ho la mia famosa gridview generale dove compare la lista delle commesse, questa griglia la popolo dal code behind perchè l'utente può filtrare le commesse in base a certi paramentri.
Quindi sopra la griglia ci sono delle dropdown e dei texbox dentro i quali l'utente può scrivere. Una volta cliccato il tasto "cerca" viene chiamata la funzione "carica" che si occupa di creare la stringa di select (in base ai valori inseriti dall'utente) e fa il bind della gridview.
Ora il probelma è che ho messo il sort nella gridview e quando l'utente clicca sull'header della colonna spariscono i dati perchè il sort genera postback.
Ho provato quindi a mettere nel pageload

if Page.IsPostBack then
  carica()
end if

ma se faccio così il sort funziona bene ma non mi funzionano più i pulsanti stampa, stampapdf e creapdf in quanto viene fatto il bind della gridview ad ogni postback e perdo i chechbox selezionati...

Non so se mi sono spiegato bene, nel caso chiedimi pure.
Grazie mille!
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao, prego :]

prova ad effettuare il databinding della GridView nel Page_Init (o Page_InitComplete). In questo modo i controlli, dopo essere stati ricreati, avranno la possibilità di recuperare il proprio valore leggendolo dai dati del POST.

Infatti, guarda questa immagine che illustra gli eventi che si verificano durante il ciclo di vita di una pagina asp.net.
http://i.msdn.microsoft.com/dynimg/IC386473.png

Dato che i controlli del form come le checkbox e le dropdownlist implementano IPostBackDataHandler, Asp.Net ne invocherà il metodo LoadPostData affinché possano ripristinare i loro valori.
Nell'immagine, la chiamata a questo metodo si trova subito prima del PreLoad ma dopo l'InitComplete.

Quindi, se effettuassi il databinding nel Page_Load sarebbe ormai troppo tardi e i controlli non potrebbero più svolgere questa operazione di recupero.

ciao
Modificato da BrightSoul il 24 aprile 2012 00.14 -

Enjoy learning and just keep making
54 messaggi dal 13 settembre 2010
Perfetto!!
Facendo il databinding nel Page_InitComplete funziona ottimamente.

Per caso hai idea di come implementare una gridview con l'header che resta fisso in caso di scroll?
Ho provato varie soluzioni css ma funzionano solo con IE inferiore alla versione 8.

Come sempre ti ringrazio!
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,
in tabella puoi avere due elementi figli che ti facilitano il problema: il <thead> per l'intestazione e il <tbody> che raccoglie tutte le righe di dati. Sfortunatamente il <tbody> in IE non è scrollabile ed è quello il motivo per cui certi gli esempi tipo questo non funzionano.

Se usi jQuery puoi dare un'occhiata anche a questo plugin che non è una soluzione in puro CSS ma usa anche del javascript.

Ad ogni modo, per default la GridView non genera gli elementi <thead> e <tbody> che ti servono, ma puoi farglieli generare in questo modo. Nel codefile della pagina metti:
protected void Page_PreRenderComplete(object sender, EventArgs e)
{
  gridView.UseAccessibleHeader = true;
  gridView.HeaderRow.TableSection = TableRowSection.TableHeader;
}
Queste due righe di codice devono essere eseguite solo a DataBinding avvenuto perché la proprietà HeaderRow della GridView è null prima di allora. L'evento PreRenderComplete della pagina è un buon momento per accedervi perché si verifica dopo gli eventi di binding.

Osserva l'html generato dalla GridView e verifica che gli elementi <thead> e <tbody> siano ora presenti all'interno della tabella.

Adesso il markup della tabella è pronto. Devi decidere se realizzare lo scroll con il plugin sopra citato o se provare con una soluzione in CSS puro.
Dicevo prima che il <tbody> non è scrollabile, ma nulla ti vieta di avvolgere la tabella di una div ad altezza fissa e rendere scrollabile quella.

<div id="contenitore">
    <asp:GridView ID="gridView" runat="server">
    </asp:GridView>
</div>
Prova ad usare questo codice CSS.
<style type="text/css">
 /* rendo scrollabile il contenitore impostandogli una height di 400 pixel e l'overflow:scroll */
 #contenitore {height:400px; width:100%; overflow:scroll; position:relative; margin-top:26px;}
 /* cambio il posizionamento dell'intestazione, in modo che sia fixed. Così non scrollerà insieme a tutto il resto */
 #gridView>thead {position:fixed; margin-top:-26px; background-color:#CCC;}
</style>

Avrai dei problemi con la larghezza delle colonne... Le celle dell'intestazione sembreranno non allineate con le celle del contenuto. Puoi risolverlo impostando una larghezza fissa alle celle, che sia in pixel o in percentuale.

gdalbell ha scritto:

Come sempre ti ringrazio!

prego :) ciao!
Modificato da BrightSoul il 15 maggio 2012 22.44 -

Enjoy learning and just keep making
54 messaggi dal 13 settembre 2010
Ok chiaro,
ma sono obbligato a fissare una larghezza unica per tutte le colonne della gridview in quanto la larghezza la devo impostare da css ??
 #gridview>thead>tr>th {width:125px;}


Perchè nel mio caso le colonne della gridview hanno larghezze diverse una dall'altra...
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,

gdalbell ha scritto:

sono obbligato a fissare una larghezza unica per tutte le colonne

no, sei libero di impostare una larghezza differente per ciascuna colonna. Per farlo, devi prima assegnare una classe CSS a ciascuna colonna della tua gridview. Ad esempio:
    <asp:GridView ID="gridView" AutoGenerateColumns="false" runat="server">
    <Columns>
        <asp:BoundField DataField="NomeCampo1" HeaderStyle-CssClass="colonna1" ItemStyle-CssClass="colonna1" />
        <asp:BoundField DataField="NomeCampo2" HeaderStyle-CssClass="colonna2" ItemStyle-CssClass="colonna2" />
    </Columns>
    </asp:GridView>
Qui ho usato gli attributi HeaderStyle-CssClass e ItemStyle-CssClass per assegnare una classe CSS alle celle d'intestazione e alle celle dati, rispettivamente. Usa il nome di tale classe per impostare la larghezza di ciascuna colonna.
#gridView .colonna1 {width:100px;}
#gridView .colonna2 {width:200px;}


In alternativa, se le tue colonne sono autogenerate e quindi non hai un elemento <Columns> all'interno della GridView per poter assegnare i nomi di classe, allora puoi anche usare questo sistema:
#gridView th, #gridView td {width:50px;} /* celle della prima colonna */
#gridView th+th, #gridView td+td {width:100px;} /* celle della seconda colonna */
#gridView th+th+th, #gridView td+td+td {width:150px;} /* celle della terza colonna */
/* e così via */

Bruttino ma più compatibile della pseudoclasse :nth-child(n) che pure ti permetterebbe di risolvere il problema.
#gridView th:nth-child(1), #gridView td:nth-child(1) {width:50px;} /* celle della prima colonna */
#gridView th:nth-child(2), #gridView td:nth-child(2) {width:100px;} /* celle della seconda colonna */
#gridView th:nth-child(3), #gridView td:nth-child(3) {width:150px;} /* celle della terza colonna */
/* e così via */


ciao
Modificato da BrightSoul il 16 maggio 2012 21.02 -

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.