Esame 70-526 http://blogs.ugidotnet.org/idamiani/category/Esame 70-526.aspx Serie di post sull'esame 70-526 per conseguire la certificazione MCPD it-IT Igor Damiani Subtext Version 2.6.0.0 Ed invece il mio esame 70-526 &egrave; sempre l&igrave;... http://blogs.ugidotnet.org/idamiani/archive/2007/02/19/71155.aspx <p>E invece io non ce la faccio. Mi riferisco all'<a href="http://blogs.ugidotnet.org/Crad/archive/2007/02/19/71139.aspx" target="_blank">ottimo successo di Marco nell'esame 70-548</a>. Sono fatto un po' diversamente, io. Ho i periodi in cui ho voglia di studiare per l'esame, ed altri in cui invece preferisco studiare altro, come WPF. E' un brutto difetto che mi trascino dietro...anche i miei post sull'esame 70-526 subiscono rallentamenti, ma non ci posso fare nulla. Anche ai tempi della scuola ero fatto così: se una cosa non mi appassiona almeno all'80%, tendo a dimenticarmene e ad accantonarla. Se aggiungete il fatto che il mio lavoro è fatto d'altro che .NET, allora si arriva rapidamente alla conclusione che studio e bloggo solo quando ho l'ispirazione e la voglia. Peccato. E' un brutto difetto, perchè magari quello che potrei fare in 15 giorni, me lo trascino dietro per un tempo indefinito. Magari potrei dare l'esame e superarlo, ma l'idea di piantare lì i post non mi piace: preferisco dare precedenza alla community e quindi la morale è "<em><font color="#ff0000">Non dare l'esame fino a quando non finisci di bloggare tutti gli argomenti per l'esame!</font></em>".</p> <p><img src="http://www.tuttogratis.it/img/emoticons/_randellate.gif" border="0"></p> <p>In fondo...&lt;cit&gt;<em>...siamo solo umani...</em>&lt;/cit&gt;</p><img src="http://blogs.ugidotnet.org/idamiani/aggbug/71155.aspx" width="1" height="1" /> Igor Damiani http://blogs.ugidotnet.org/idamiani/archive/2007/02/19/71155.aspx Mon, 19 Feb 2007 18:49:00 GMT http://blogs.ugidotnet.org/idamiani/archive/2007/02/19/71155.aspx#feedback http://blogs.ugidotnet.org/idamiani/comments/commentRss/71155.aspx http://blogs.ugidotnet.org/idamiani/services/trackbacks/71155.aspx [70-526, #8] Ancora sulla stampa: anteprima e note veloci sulla sicurezza http://blogs.ugidotnet.org/idamiani/archive/2007/02/05/69828.aspx <p>Già ai tempi dell'esame 70-316, avevamo visto gli strumenti che il FW2.0 ci mette a disposizione per produrre anteprime di stampa dei nostri documenti <a href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printdocument.aspx" target="_blank">PrintDocument</a>. Attraverso la classe <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.printpreviewdialog.aspx" target="_blank">PrintPreviewDialog</a>, abbiamo a disposizione una Windows Form che mostra l'anteprima di stampa del nostro documento. Questa Windows Form non è modificabile: così è, e così ce la teniamo. Come tutte le WF, per visualizzarle non dobbiamo fare altro che chiamare il metodo <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.form.showdialog.aspx" target="_blank">ShowDialog</a>, solo dopo aver impostato la proprietà <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.printpreviewdialog.document.aspx" target="_blank">Document</a> sull'istanza di PrintDocument di cui vogliamo generare l'anteprima. La chiamata a ShowDialog scatena la stampa del documento, che però non viene indirizzata sulla stampante di default, bensì sulla finestra di dialogo, scatenando l'esecuzione dell'evento <a href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printdocument.printpage.aspx" target="_blank">PrintPage</a> per ogni pagina come abbiamo già visto precedentemente.</p> <p>La WF visualizzata dal PrintPreviewDialog possiede alcune caratteristiche particolari. Vediamole perchè ci torneranno utili più avanti:</p> <ol> <li>La superficie della form è occupata per la maggior parte da un rettangolo bianco che mostra l'anteprima</li> <li>In alto a sinistra c'è una piccola toolbar, che ci consente di stampare il documento, di impostare lo zoom, di decidere quante pagine vogliamo vedere alla volta (1, 2, 3, 4 e 6) e di chiudere la finestra</li> <li>In alto a destra c'è un controllo <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=NumericUpDown+Class+(System.Windows.Forms)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.windows.forms.numericupdown.aspx" target="_blank">NumericUpDown</a> che ci permette di scorrere le pagine che compongono il documento</li></ol> <p><strong>Il controllo PrintPreviewControl</strong><br>Con il FW2.0 c'è una possibilità in più. Grazie all'implementazione della classe <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.printpreviewcontrol.aspx" target="_blank"><strong>PrintPreviewControl</strong></a>, infatti, possiamo creare una finestra di anteprima custom, personalizzandola e aggiungendo features come desideriamo noi. Il "rettangolo bianco" di cui ho parlato al punto (1) non è nient'altro che un controllo PrintPreviewControl, che renderizza un PrintDocument. Come tutti i controlli, anche questo deve essere posizionato su una Windows Form normalissima, che quindi possiamo disegnare come vogliamo noi.</p> <p>PrintPreviewControl espone alcune proprietà che ci permettono di emulare il comportamento della WF standard mostrata da PrintPreviewDialog. Le proprietà sono:</p> <ol> <li>la proprietà <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.printpreviewcontrol.document.aspx" target="_blank">Document</a> è la più importante: stabilisce quale PrintDocument mostrare nell'anteprima</li> <li><a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.printpreviewcontrol.columns.aspx" target="_blank">Columns</a> e <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.printpreviewcontrol.rows.aspx" target="_blank">Rows</a> permettono di stabilire quante pagine vedere nell'anteprima (rispettivamente in senso orizzontale e verticale)</li> <li><a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.printpreviewcontrol.zoom.aspx" target="_blank">Zoom</a> permette di stabilire lo zoom iniziale dell'anteprima</li> <li><a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.printpreviewcontrol.startpage.aspx" target="_blank">StartPage</a> permette di stabilire la pagina del PrintDocument da visualizzare</li> <li>la proprietà <a title="UseAntiAlias" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.printpreviewcontrol.useantialias.aspx">UseAntiAlias</a>, come dice il nome stesso, renderizza i font con un effetto di anti-aliasing per migliorarne la leggibilità</li></ol> <p>Agendo su queste proprietà, quindi, possiamo riprodurre tutte le funzionalità della dialog esposta da PrintPreviewDialog. Ma possiamo andare un po' più in là, aggiungendo features (controlli, per esempio) alla WF capaci di agire sul PrintDocument e di modificarne la stampa.</p> <p><strong>La sicurezza - PrintingPermission<br></strong>Il FW2.0 ci permette di regolare l'accesso alle stampanti da parte del nostro managed code, coinvolgendo la classe PrintingPermission, che eredita direttamente da <a title="System.Security.CodeAccessPermission" href="http://msdn2.microsoft.com/en-us/library/system.security.codeaccesspermission.aspx">CodeAccessPermission</a>. Tale classe espone la proprietà Level, che assume i valori determinati dall'enum <a href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printingpermissionlevel.aspx" target="_blank">PrintingPermissionLevel</a>&nbsp;(AllPrinting, DefaultPrinting, NoPrinting e SafePrinting). La classe PrintingPermission dispone oltre agli altri dei metodi <a href="http://msdn2.microsoft.com/en-us/library/system.security.codeaccesspermission.assert.aspx" target="_blank">Assert</a> e <a href="http://msdn2.microsoft.com/en-us/library/system.security.codeaccesspermission.demand.aspx" target="_blank">Demand</a>. Vi consiglio una lettura agli articoli su MSDN intitolati <a title="Security Permissions" href="http://msdn2.microsoft.com/en-us/library/5ba4k1c5.aspx">Security Permissions</a>&nbsp;e <a title="Requesting Permissions" href="http://msdn2.microsoft.com/en-us/library/yd267cce.aspx">Requesting Permissions</a>.</p><img src="http://blogs.ugidotnet.org/idamiani/aggbug/69828.aspx" width="1" height="1" /> Igor Damiani http://blogs.ugidotnet.org/idamiani/archive/2007/02/05/69828.aspx Mon, 05 Feb 2007 15:44:00 GMT http://blogs.ugidotnet.org/idamiani/archive/2007/02/05/69828.aspx#feedback 1 http://blogs.ugidotnet.org/idamiani/comments/commentRss/69828.aspx http://blogs.ugidotnet.org/idamiani/services/trackbacks/69828.aspx [70-526, #7] Stampare con il Framework 2.0 http://blogs.ugidotnet.org/idamiani/archive/2007/01/29/69026.aspx <p>E' talmente tanto che uso Reporting Services di SQL Server 2005 che ho spazzato dalla mia mente tutto quello che ho studiato per il 70-316. Ma è bastato un esercizio di auto-ipnosi regressiva per ricordare tutto quello che c'è da sapere - ovviamente, sto scherzando.</p> <p><strong>Le classi</strong><br>Quando si&nbsp;tratta di stampare con il FX2.0, dobbiamo focalizzare la nostra attenzione su una manciata di classi:</p> <p><strong>PrintDocument</strong>, che rappresenta un documento da stampare<br><strong>PrintDialog</strong>, che rappresenta la dialog standard per scegliere la stampante su cui inviare l'output<br><strong>PrintPreviewDialog</strong>, che permette di mostrare all'utente una finestra per l'anteprima di stampa<br><strong>PageSetupDialog</strong>, che permette all'utente di impostare margini, orientamento e stampante</p> <p>Il più importante di tutti è il <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PrintDocument+Class+(System.Drawing.Printing)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printdocument.aspx" target="_blank"><strong>PrintDocument</strong></a>, che è il documento vero e proprio e spesso è un input per le altre dialog elencate sopra. Prima di poter utilizzare i dialog standard di Windows, dobbiamo quindi generare un documento e capire come impaginare il contenuto, come generare più pagine e così via. Creare un oggetto <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PrintDocument+Class+(System.Drawing.Printing)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printdocument.aspx" target="_blank">PrintDocument</a> implica la buona conoscenza di GDI+, perchè ogni cosa renderizzata su un PrintDocument viene disegnata attraverso la classe <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=Graphics+Class+(System.Drawing)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.drawing.graphics.aspx" target="_blank"><strong>Graphics</strong></a> e tutti i suoi metodi.</p> <p>La cosa più semplice che possiamo fare per cominciare a lavorare con un PrintDocument è quello di trascinarlo dalla Toolbox su una Windows Form. Il PrintDocument comparirà nella tray-area della WF stessa. Siccome però siamo sviluppatori, vediamo come fare tutto via codice, giusto per continuare a battere sulla tastiera e a dimenticare un po' il mouse. :-)</p> <p></p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:b704ead5-5057-40c6-9808-5bd1ac1dd05a" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #000000; ">PrintDocument doc </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> PrintDocument(); doc.BeginPrint </span><span style="color: #000000; ">+=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> PrintEventHandler(doc_BeginPrint); doc.EndPrint </span><span style="color: #000000; ">+=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> PrintEventHandler(doc_EndPrint); doc.PrintPage </span><span style="color: #000000; ">+=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> PrintPageEventHandler(doc_PrintPage); doc.QueryPageSettings </span><span style="color: #000000; ">+=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> QueryPageSettingsEventHandler(doc_QueryPageSettings);</span></div></pre></div> <p></p> <p>Per cominciare la stampa diretta sulla stampante di default di Windows, è sufficiente chiamare il metodo <strong>Print</strong> della classe PrintDocument. La chiamata a questo metodo non visualizza nulla, non c'è interazione con l'utente. Il FX usa il PrintDocument, genera il contenuto per ciascuna pagina e stampa.</p> <p>La classe PrintDocument espone 4 importanti eventi. <a href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printdocument.beginprint.aspx" target="_blank"><strong>BeginPrint</strong></a> viene sollevato all'inizio della stampa, prima che la prima pagina venga stampata. <a href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printdocument.endprint.aspx" target="_blank"><strong>EndPrint</strong></a> viene sollevato al termine della stampa. <a href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printdocument.printpage.aspx" target="_blank"><strong>PrintPage</strong></a> e <a href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printdocument.querypagesettings.aspx" target="_blank"><strong>QueryPageSettings</strong></a> vengono sollevati ad ogni pagina: il primo viene sollevato quando occorre generare il contenuto della pagina per l'invio alla stampante. <a href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printdocument.querypagesettings.aspx" target="_blank"><strong>QueryPageSettings</strong></a> viene sollevato prima ancora di PrintPage, e permette di impostare un particolare formato per ciascuna pagina (orientamento, margini e così via).</p> <p>Il più importante fra questi è indubbiamente PrintPage. Il parametro <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PrintPageEventArgs+Class+(System.Drawing.Printing)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printpageeventargs.aspx" target="_blank">PrintPageEventArgs</a> permette di ottenere un riferimento a Graphics, attraverso&nbsp;il quale possiamo disegnare testo, grafica e così via. Questa classe espone alcune proprietà essenziali per la gestione della stampa:&nbsp;possiamo impostare la&nbsp;proprietà <a title="Cancel" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printpageeventargs.cancel.aspx">Cancel</a>&nbsp;a false per annullare il processo di stampa, possiamo impostare <a title="HasMorePages" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printpageeventargs.hasmorepages.aspx">HasMorePages</a>&nbsp;a true per indicare che ci sono ancora pagine da stampare. Difatti, l'evento PrintPage viene continuamente chiamato fintantochè <a title="HasMorePages" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printpageeventargs.hasmorepages.aspx">HasMorePages</a>&nbsp;continua a valere true. La proprietà <a title="PageBounds" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printpageeventargs.pagebounds.aspx">PageBounds</a>&nbsp;rappresenta la dimensione totale della pagina su cui si sta stampando, mentre <a title="MarginBounds" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printpageeventargs.marginbounds.aspx">MarginBounds</a>&nbsp;considera anche eventuali margini della pagina stessa. La proprietà <a title="PageSettings" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.printpageeventargs.pagesettings.aspx">PageSettings</a>&nbsp;consente l'accesso a tutta una serie di informazioni sulla pagina corrente (<a title="Bounds" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.pagesettings.bounds.aspx">Bounds</a>, <a title="Margins" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.pagesettings.margins.aspx">Margins</a>, <a title="PaperSize" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.pagesettings.papersize.aspx">PaperSize</a>, <a title="PrintableArea" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.pagesettings.printablearea.aspx">PrintableArea</a>, <a title="PrinterResolution" href="http://msdn2.microsoft.com/en-us/library/system.drawing.printing.pagesettings.printerresolution.aspx">PrinterResolution</a>).</p> <p>Per un esempio più pratico e per maggiori informazioni, rimando <a href="http://blogs.ugidotnet.org/idamiani/archive/2005/07/15/23476.aspx" target="_blank">al mio vecchio post</a> sull'esame 70-316.</p> <p><strong>In breve, la classe PrintPreviewDialog</strong><br>Se volessimo mostrare un'anteprima di stampa, possiamo utilizzare il componente <a title="PrintPreviewDialog Class (System.Windows.Forms)" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PrintPreviewDialog+Class+(System.Windows.Forms)+&amp;url=http://msdn2.microsoft.com/en-gb/library/system.windows.forms.printpreviewdialog.aspx">PrintPreviewDialog</a>. Per utilizzare, non dobbiamo fare altro che impostare la proprietà <a href="http://msdn2.microsoft.com/en-gb/library/system.windows.forms.printpreviewdialog.document.aspx" target="_blank">Document</a> su un oggetto PrintDocument valido. La chiamata al metodo <a title="ShowDialog" href="http://msdn2.microsoft.com/en-gb/library/system.windows.forms.form.showdialog.aspx">ShowDialog</a>&nbsp;mostra l'anteprima, scatenando prima gli eventi relativi al PrintDocument di cui abbiamo discusso prima.</p><img src="http://blogs.ugidotnet.org/idamiani/aggbug/69026.aspx" width="1" height="1" /> Igor Damiani http://blogs.ugidotnet.org/idamiani/archive/2007/01/29/69026.aspx Mon, 29 Jan 2007 13:16:00 GMT http://blogs.ugidotnet.org/idamiani/archive/2007/01/29/69026.aspx#feedback http://blogs.ugidotnet.org/idamiani/comments/commentRss/69026.aspx http://blogs.ugidotnet.org/idamiani/services/trackbacks/69026.aspx 980 birre medie http://blogs.ugidotnet.org/idamiani/archive/2007/01/26/68689.aspx <p>Un <em>certo tizio</em> stasera&nbsp;offrirà <strong>980</strong> birre medie. Non chiedetemi chi le deve bere (io una di sicuro), prendetelo più come un abbonamento a lunga scadenza. :-) Complimentissimi a <em>un certo tizio</em>. :-D</p> <p>A proposito, mi aspetto un commento, altrimenti qua vengo preso per pazzo!</p><img src="http://blogs.ugidotnet.org/idamiani/aggbug/68689.aspx" width="1" height="1" /> Igor Damiani http://blogs.ugidotnet.org/idamiani/archive/2007/01/26/68689.aspx Fri, 26 Jan 2007 11:32:00 GMT http://blogs.ugidotnet.org/idamiani/archive/2007/01/26/68689.aspx#feedback 4 http://blogs.ugidotnet.org/idamiani/comments/commentRss/68689.aspx http://blogs.ugidotnet.org/idamiani/services/trackbacks/68689.aspx [70-526, #6] Carrellata: ToolTip, ProgressBar ed HelpProvider http://blogs.ugidotnet.org/idamiani/archive/2007/01/15/66888.aspx <p>Oggi pensiamo ad un post dai contenuti leggeri, affrontando l'utilizzo di controlli semplici ed efficaci da poter usare sulle nostre Windows Forms. L'esame 70-526 ci chiede di utilizzare i controlli <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=ToolTip+Class+(System.Windows.Forms)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.aspx" target="_blank">ToolTip</a>, <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=ProgressBar+Class+(System.Windows.Forms)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.windows.forms.progressbar.aspx" target="_blank">ProgressBar</a>, <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=HelpProvider+Class+(System.Windows.Forms)+&amp;url=http://msdn2.microsoft.com/en-US/library/system.windows.forms.helpprovider.aspx" target="_blank">HelpProvider</a> e&nbsp;<a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=ErrorProvider+Class+(System.Windows.Forms)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.windows.forms.errorprovider.aspx" target="_blank">ErrorProvider</a>. Per quest'ultimo vi rimando, oltre che ai vari links&nbsp;ufficiali Microsoft,&nbsp;<a href="http://blogs.ugidotnet.org/idamiani/archive/2005/07/08/22444.aspx" target="_blank">al mio stesso post</a> scritto un po' di tempo fa relativamente all'esame 70-316: nel FW2.0 da questo punto di vista non è cambiato nulla, per cui... Per gli altri controlli, continuate a leggere.</p> <p><strong>Componente&nbsp;ToolTip<br></strong>Il controllo ToolTip è in realtà un componente, e serve a mostrare per l'appunto un piccolo tooltip sui controlli. Lo si trascina dalla toolbox di VS2005 su una qualsiasi Windows Forms del nostro progetto. Il componente finisce nella tray-area della WF, dove possiamo settarne la proprietà principali. ToolTip implementa l'interfaccia <a href="http://msdn2.microsoft.com/en-us/library/system.componentmodel.iextenderprovider.aspx" target="_blank">IExtenderProvider</a> (che prevede l'implementazione del solo metodo <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.canextend.aspx" target="_blank">CanExtend</a>): ciò significa che, banalmente, il ToolTip non fa nulla da solo, ma aggiunge alcune proprietà ai controlli presenti sulla Windows Forms stessa. Nella tray-area definiamo proprietà generiche - come l'aspetto visivo - del componente Tooltip, ma il contenuto vero e proprio&nbsp;viene definito sul controllo che fa uso del tooltip. Vediamo di spiegarci meglio, dando un'occhiata alle proprietà del componente Tooltip; le principali sono:</p> <ol> <li><a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.active.aspx" target="_blank">Active</a>, che attiva o meno la visualizzazione dei tooltip</li> <li><a title="BackColor" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.backcolor.aspx">BackColor</a>&nbsp;e <a title="ForeColor" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.forecolor.aspx">ForeColor</a>, che determinano il colore di sfondo e del testo dei tooltip</li> <li><a title="IsBalloon" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.isballoon.aspx">IsBalloon</a>, che determina se i tooltip devono apparire come dei ballon</li> <li><a title="ToolTipIcon" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.tooltipicon.aspx">ToolTipIcon</a>, che determina un'eventuale icona</li> <li><a title="ToolTipTitle" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.tooltiptitle.aspx">ToolTipTitle</a>&nbsp;serve per indicare un titolo che deve apparire nei tooltip</li> <li><a title="UseAnimation" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.useanimation.aspx">UseAnimation</a>&nbsp;e <a title="UseFading" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.usefading.aspx">UseFading</a>&nbsp;determinano se il tooltip deve apparire con un'animazione e se deve scomparire con un fade out</li></ol> <p>Dopo aver configurato il ToolTip, proviamo a selezionare un qualsiasi altro dei controlli sulla Windows Forms (Button, TextBox, ListBox e via dicendo). A tutti questi controlli è stata aggiunta una proprietà di tipo stringa, che determina quindi il contenuto effettivo del tooltip per quel specifico controllo che abbiamo selezionato.</p> <p>Il ToolTip espone l'evento <a title="Draw" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.tooltip.draw.aspx">Draw</a>&nbsp;che possiamo gestire con un opportuno event handler per intercettare il disegno del tooltip da parte del framework. L'event handler fa uso della classe <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=DrawToolTipEventArgs+Class+(System.Windows.Forms)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.windows.forms.drawtooltipeventargs.aspx" target="_blank">DrawToolTipEventArgs</a>, che espone un'istanza di <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.drawtooltipeventargs.graphics.aspx" target="_blank">Graphics</a> e <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.drawtooltipeventargs.font.aspx" target="_blank">Font</a>, per esempio, che possiamo sfruttare per customizzare l'aspetto del ToolTip.</p> <p><strong>Controllo ProgressBar<br></strong>Direi che questo controllo non ha bisogno di presentazioni, giusto? :-) Esisteva fin dai tempi di Visual Basic 3, probabilmente, ed inoltre è uno dei controlli che più mi stanno simpatici. La ProgressBar dà un'indicazione visuale dello stato di un'elaborazione più o meno lunga, informando l'utente a che punto siamo e quanto manca alla fine. Non in termini di tempo, è chiaro, ma relativamente parlando. Gran parte dell'interfaccia della ProgressBar è ereditata da Control, ovviamente, ma ne aggiunge qualcuna necessaria: <a title="Minimum" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.progressbar.minimum.aspx">Minimum</a>&nbsp;e <a title="Maximum" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.progressbar.maximum.aspx">Maximum</a>&nbsp;determinano il valore minimo e massimo che la proprietà <a title="Value" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.progressbar.value.aspx">Value</a>&nbsp;può assumere. In base a questi valori, il controllo si disegna in modo opportuno. Esempio banale: se Minimum = 0, Maximum = 100 e Value = 50, la ProgressBar disegnerà una barra che arriverà fino a metà del controllo. La proprietà <a title="Style" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.progressbar.style.aspx">Style</a>&nbsp;determina lo stile di questa barra, che può assumere i valori dell'enum <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.progressbarstyle.aspx" target="_blank">ProgressBarStyle</a>&nbsp;(Blocks, Continuous e Marquee).</p> <p>Come potete ben immaginare, la ProgressBar viene soprattutto usata per notificare all'utente lo stato di un'operazione di lunga durata, per far capire che il vostro applicativo non si è impallato ma sta facendo quello che deve fare. Questo vuol dire utilizzarla quindi in combinazione con thread secondari oppure utilizzando il componente <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=BackgroundWorker+Component+&amp;url=http://msdn2.microsoft.com/en-us/library/c8dcext2.aspx" target="_blank">BackgroundWorker</a>, <a href="http://blogs.ugidotnet.org/idamiani/archive/2006/02/28/35763.aspx" target="_blank">di cui ho già parlato in passato</a> per l'esame 70-536. Esame in cui ho preso un punteggio infimo.&nbsp;Il&nbsp;BackgroundWorker mi è rimasto in testa, al punto che ne ho scritto un articolo su uno dei numeri di IoProgrammo uscito nei mesi scorsi.</p> <p><strong>Componente HelpProvider<br></strong>Il componente HelpProvider serve per fornire assistenza all'utente su una Windows Form. Si basa sulla classe <a href="http://msdn2.microsoft.com/en-US/library/system.windows.forms.help.aspx" target="_blank">Help</a> che incapsula tutto l'engine per gestire help in formato HTML. Come il ToolTip, l'HelpProvider aggiunge un po' di proprietà ai controlli su una Windows Forms. Tali proprietà impostano le modalità di help che l'applicativo fornisce all'utente. Per testarlo velocemente e capirne il funzionamento, seguite i seguenti passi:</p> <ol> <li>Aggiungete una nuova Windows Form al progetto</li> <li>Trascinate un HelpProvider dalla toolbox di VS2005 sulla WF</li> <li>Aggiungete una TextBox alla stessa WF</li> <li>Settate la proprietà HelpString della TextBox (aggiunta dall'HelpProvider) con la stringa: "Eccoti l'aiuto: guarda ed impara!"</li></ol> <p>Eseguite il progetto. Quando la WF appare, date il focus alla TextBox e premete F1. Il FW2.0 fa apparire un tooltip (graficamente diverso dal classico ToolTip) che mostra la stringa impostata per quel controllo.</p> <p>Ovviamente, l'HelpProvider può essere sfruttato in modo più raffinato. Non si limita alla visualizzazione di semplici tooltip. La proprietà <a title="HelpNamespace" href="http://msdn2.microsoft.com/en-US/library/system.windows.forms.helpprovider.helpnamespace.aspx">HelpNamespace</a>&nbsp;ci permette di impostare il file di help da utilizzare, che può essere in formato CHM o HTML. Ad ogni controllo possiamo quindi associare <a href="http://msdn2.microsoft.com/en-US/library/system.windows.forms.helpprovider.sethelpkeyword.aspx" target="_blank">una keyword</a>, che verrà ricercata come topic nel file di help.</p><img src="http://blogs.ugidotnet.org/idamiani/aggbug/66888.aspx" width="1" height="1" /> Igor Damiani http://blogs.ugidotnet.org/idamiani/archive/2007/01/15/66888.aspx Mon, 15 Jan 2007 12:14:00 GMT http://blogs.ugidotnet.org/idamiani/archive/2007/01/15/66888.aspx#feedback http://blogs.ugidotnet.org/idamiani/comments/commentRss/66888.aspx http://blogs.ugidotnet.org/idamiani/services/trackbacks/66888.aspx [70-526, #5] Utilizzare la PropertyGrid http://blogs.ugidotnet.org/idamiani/archive/2007/01/11/66034.aspx <p>Anche se magari non ve ne rendete conto, utilizzate il controllo <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.aspx" target="_blank"><strong>PropertyGrid</strong></a>&nbsp;tutte le volte che premete F4 all'interno dell'IDE di Visual Studio 2005. La PropertyGrid non è nient'altro che il componente .NET che implementa la Property Window dell'IDE. La cosa interessante è che possiamo utilizzarla all'interno dei nostri progetti .NET.</p> <p>La PropertyGrid mostra tutte le proprietà di un oggetto managed nello stesso identico modo attuato dalla Property Window. E' sufficiente impostare la proprietà <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.selectedobject.aspx" target="_blank">SelectedObject</a> (o <a title="SelectedObjects" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.selectedobjects.aspx">SelectedObjects</a>&nbsp;per più oggetti contemporaneamente) esposta da questo controllo. La PropertyGrid rifletterà automaticamente questa impostazione, mostrando le proprietà dell'oggetto. Attraverso l'interfaccia, possiamo personalizzarne e controllarne l'aspetto.</p> <p>La proprietà <a title="PropertySort" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.propertysort.aspx">PropertySort</a>&nbsp;permette di impostare attraverso l'<a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.propertysort.aspx" target="_blank">enum omonimo</a> la modalità di visualizzazione che deve assumere la PropertyGrid (alfabetica, per categorie od entrambe), esattamente come accade nell'IDE. Le proprietà <a title="ViewBackColor" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.viewbackcolor.aspx">ViewBackColor</a>&nbsp;e <a title="ViewForeColor" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.viewforecolor.aspx">ViewForeColor</a>&nbsp;permettono di impostare rispettivamente il colore di sfondo e del testo nella PropertyGrid. La proprietà <a title="CategoryForeColor" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.categoryforecolor.aspx">CategoryForeColor</a>&nbsp;regola il colore del testo utilizzato nelle barre relative alla categoria. Una cosa importante: quando si cambia&nbsp;una proprietà dell'oggetto referenziato da SelectedObject, il cambiamento non si riflette automaticamente nella PropertyGrid - per farlo, è necessaria una chiamata al metodo <a title="Refresh" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.refresh.aspx">Refresh</a>. Il metodo <a title="ExpandAllGridItems" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.expandallgriditems.aspx">ExpandAllGridItems</a>&nbsp;espande automaticamente tutti gli elementi che possono essere espansi (leggesi: categorie oppure proprietà complesse, come <a title="Size" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.size.aspx">Size</a>, <a title="Location" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.location.aspx">Location</a>, <a title="Font" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.font.aspx">Font</a>&nbsp;- tutte derivate da <a title="Control" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.aspx">Control</a>).</p> <p>Personalmente, ho utilizzato questo controllo all'interno di <a href="http://www.codeplex.com/HappySign" target="_blank">Happy Sign</a> (adesso è stato rimosso) per consentire all'utente di cambiare le Signature senza troppe complicazioni, proprio perchè potete usare questo controllo con qualsiasi oggetto, compresi quelli del vostro domain model.</p> <p><strong>Gli eventi della PropertyGrid<br></strong>La Property Grid espone un certo numero di eventi. Tra i più interessanti segnalo:</p> <ol> <li><a title="SelectedGridItemChanged" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.selectedgriditemchanged.aspx">SelectedGridItemChanged</a>, per reagire quando cambiamo riga (e quindi proprietà selezionata) all'interno della PropertyGrid</li> <li><a title="SelectedObjectsChanged" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.selectedobjectschanged.aspx">SelectedObjectsChanged</a>, per reagire quando cambia la proprietà SelectedObject</li> <li><a title="PropertyValueChanged" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertygrid.propertyvaluechanged.aspx">PropertyValueChanged</a>, per reagire quando cambiamo il valore di una proprietà all'interno della PropertyGrid</li></ol> <p>L'evento <strong>SelectedGridItemChanged</strong>&nbsp;utilizza la classe <a title="GridItem" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.griditem.aspx">GridItem</a>&nbsp;che, per dirla come la dice MSDN, <em>implements one row in a PropertyGrid</em>. GridItem espone la proprietà <a title="Expandable" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.griditem.expandable.aspx">Expandable</a>, che ci dice se la riga può essere espansa per mostrare le subproperties della proprietà selezionata: questo accade, per esempio, quando selezioniamo <a title="Size" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.size.aspx">Size</a>, che espone <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.width.aspx" target="_blank">Width</a> ed <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.height.aspx" target="_blank">Height</a>. La trovo però una spiegazione non sufficiente, perchè Expandable ritorna true anche quando selezioniamo una categoria, per cui stiamo attenti. La proprietà <a title="Label" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.griditem.label.aspx">Label</a>&nbsp;ci ritorna la caption della riga corrente, mentre <a title="Value" href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.griditem.value.aspx">Value</a>&nbsp;il valore della proprietà (intesa come object, com'è ovvio che sia).</p> <p>L'evento <strong>SelectedObjectsChanged</strong> non ha nulla di particolare da segnalare.</p> <p>L'evento <strong>PropertyValueChanged</strong> viene sollevato quando modifichiamo il valore di una proprietà. L'event handler, oltre al classico object sender a cui siamo abituati, utilizza la classe <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.propertyvaluechangedeventargs.aspx" target="_blank">PropertyValueChangedEventArgs</a> che espone il membro ChangedItem che non è nient'altro che il GridItem sul quale abbiamo fatto la modifica. La proprietà OldValue invece è un object che contiene il vecchio valore, prima della modifica.</p> <p><strong>PropertyGrid? Conoscere&nbsp;bene anche il namespace System.ComponentModel!</strong><br>Utilizzare la PropertyGrid senza conoscere un po' il namespace <a title="System.ComponentModel" href="http://msdn2.microsoft.com/zh-cn/library/system.componentmodel(VS.71).aspx">System.ComponentModel</a>&nbsp;è quasi inutile. Questo namespace contiene l'implementazione di un certo numero di classi&nbsp;Attribute molto utili a questo scopo. Ricordo ancora (a grandi linee, non esageriamo) <a href="http://www.ugidotnet.org/workshops/workshops_detail.aspx?ID=17dce405-5102-4fd7-947a-c0abb6543f4e" target="_blank">la sessione di Corrado</a> datata 14 Luglio 2005, durante la quale si vedeva come creare Windows Control. Quel giorno vedemmo come creare Windows Control capaci di esporre/ordinare/organizzare le loro proprietà in modo efficiente. Le stesse logiche sono valide anche in questo contesto, ovviamente, perchè alla fin fine - come ho detto prima - la PropertyGrid è lo stesso identico controllo dell'IDE di VS2005. Per esempio, utilizzare <a title="CategoryAttribute" href="http://msdn2.microsoft.com/en-us/library/system.componentmodel.categoryattribute(VS.71).aspx">CategoryAttribute</a>&nbsp;permette di posizionare una certa proprietà all'interno di una categoria di nostra scelta. L'attributo <a title="DefaultValueAttribute" href="http://msdn2.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute(VS.71).aspx">DefaultValueAttribute</a>&nbsp;permette di impostare il valore di default di una certa proprietà; alla PropertyGrid serve per sapere quando deve utilizzare il grassetto nell'indicare il valore stesso (e per sapere quando serializzare il codice nel <em>nomeform</em>.Designer.cs). <a title="DescriptionAttribute" href="http://msdn2.microsoft.com/en-us/library/system.componentmodel.descriptionattribute(VS.71).aspx">DescriptionAttribute</a>&nbsp;serve per indicare una descrizione per una certa proprietà, che appare nella parte inferiore della PropertyGrid. In generale, quindi, tutto il meccanismo da studiare per costruire controlli per un certo grado di user-experience a design-time (editor custom per una determina proprietà) viene applicato anche con la PropertyGrid.</p> <p>Ricordiamoci che l'esame 70-526 ci tartassa anche sullo sviluppo di controlli per Windows Forms (sia da zero che ereditati da controlli .NET standard): sapere bene il <a title="System.ComponentModel" href="http://msdn2.microsoft.com/zh-cn/library/system.componentmodel(VS.71).aspx">System.ComponentModel</a>&nbsp;quindi non riguarda solo la PropertyGrid, ma può fare la differenza tra passare e non passare l'esame!</p><img src="http://blogs.ugidotnet.org/idamiani/aggbug/66034.aspx" width="1" height="1" /> Igor Damiani http://blogs.ugidotnet.org/idamiani/archive/2007/01/11/66034.aspx Thu, 11 Jan 2007 16:18:00 GMT http://blogs.ugidotnet.org/idamiani/archive/2007/01/11/66034.aspx#feedback http://blogs.ugidotnet.org/idamiani/comments/commentRss/66034.aspx http://blogs.ugidotnet.org/idamiani/services/trackbacks/66034.aspx [70-526, #4] Leggere un documento XML con XmlReader http://blogs.ugidotnet.org/idamiani/archive/2007/01/10/65780.aspx <p>Al contrario di quanto abbiamo fatto nei due post precedenti (<a href="http://blogs.ugidotnet.org/idamiani/archive/2007/01/09/65609.aspx" target="_blank">1</a> e <a href="http://blogs.ugidotnet.org/idamiani/archive/2007/01/10/65704.aspx" target="_blank">2</a>), questa volta vedremo come aprire un documento XML in modalità read-only attraverso l'utilizzo della classe <strong><a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.aspx" target="_blank">XmlReader</a></strong>. Questo oggetto non carica tutto il documento XML in memoria, ma fornisce un veloce reader forward-only&nbsp;per leggere tutti i nodi del documento. Dimenticatevi quindi di poter saltare liberamente avanti ed indietro all'interno del documento: con XmlReader si guarda solo in avanti. :-) L'istanziazione passa attraverso un metodo statico Create, che dispone <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.create.aspx" target="_blank">di ben 12 overload</a> che permettono di leggere un documento da file, da uno Stream e&nbsp;da un TextReader ed&nbsp;utilizzando in certi casi un'istanza di XmlReaderSettings (vedere <a href="http://msdn2.microsoft.com/en-us/library/9khb6435.aspx" target="_blank">questo articolo</a> per dettagli). Nel più semplice dei casi avremo quindi una chiamata come questa:</p> <p></p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:e51673b7-9551-48ae-b5cf-d3b94b869a3e" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #0000FF; ">string</span><span style="color: #000000; "> xmlFilename </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">E:\\Books.xml</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">; </span><span style="color: #0000FF; ">using</span><span style="color: #000000; "> (XmlReader reader </span><span style="color: #000000; ">=</span><span style="color: #000000; "> XmlReader.Create(xmlFilename)) { }</span></div></pre></div> <p></p> <p>La classe XmlReader implementa l'interfaccia IDisposable, perciò, fate un favore ai bytes che compongono il vostro software (tutto compreso: dalle celle al CLR): includetela in un blocco <strong>using</strong> per rilasciare le risorse appena finito il lavoro con il vostro documento XML. :-)</p> <p>Il file XML <strong>Books.xml</strong> a cui si fa riferimento è stato creato attraverso la classe XmlDocument di cui abbiamo già parlato ieri. Una volta istanziato e creato il reader XML, utilizziamo il metodo <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.read.aspx" target="_blank">Read</a> che salta di nodo in nodo addentrandosi in profondità nel grafo XML seguendone ovviamente la struttura. Il metodo Read ritorna false quando si è arrivati alla fine del documento; lo stesso risultato è esposto dalla proprietà <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.eof.aspx" target="_blank">EOF</a>. Possiamo quindi implementare una banale iterazione che vada ad esplorare tutti i nodi del documento utilizzando un ciclo while, come riportato qui sotto:</p> <p></p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:3f7ea698-6364-47d6-bc49-60076d8d5ac6" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #0000FF; ">while</span><span style="color: #000000; "> (reader.Read()) { }</span></div></pre></div> <p></p> <p>Ad ogni iterazione, l'oggetto <strong>reader</strong> espone tutte le informazioni relative al nodo corrente. La proprietà <strong>NodeType</strong> per esempio esprime attraverso un&nbsp;enum <a title="XmlNodeType" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnodetype.aspx">XmlNodeType</a>&nbsp;il tipo del nodo corrente. La proprietà <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.depth.aspx" target="_blank">Depth</a> ci dice a quale livello di profondità ci troviamo all'interno del documento XML. La proprietà <a title="HasAttributes" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.hasattributes.aspx">HasAttributes</a>&nbsp;ci dice se il nodo corrente ha oppure no degli attributi.</p> <p>Ovviamente, esplorare un documento XML senza poterne leggere il contenuto ha poco senso. A questo scopo, XmlReader espone una serie di metodi riconoscibili dal prefisso ReadElementContentAs + <em>qualcosa</em>, dove <em>qualcosa</em> vuol dire Int, Boolean, DateTime, String, Double, Float&nbsp;e così via. In questo modo, evitiamo un casting che viene invece effettuato dal FW. In altre parole,&nbsp;invece di essere letto come stringa, viene letto con il tipo di dato più coerente per il contesto.&nbsp;Un esempio concreto: utilizzando sempre il documento XML mostrato qui, possiamo intercettare la lettura del tag &lt;year&gt;1998&lt;/year&gt; e salvare in un oggetto <strong>int</strong> il valore dell'anno.</p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:cbafd0ea-8d6f-4686-84b0-63588f031606" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #0000FF; ">string</span><span style="color: #000000; "> nodeName </span><span style="color: #000000; ">=</span><span style="color: #000000; "> reader.LocalName; </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> (nodeName.Equals(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">year</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">)) { year </span><span style="color: #000000; ">=</span><span style="color: #000000; "> reader.ReadElementContentAsInt(); Console.WriteLine(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">Anno : </span><span style="color: #000000; ">&quot;</span><span style="color: #000000; "> </span><span style="color: #000000; ">+</span><span style="color: #000000; "> year.ToString()); }</span></div></pre></div> <p>Ho inserito questo blocco di codice nel ciclo while mostrato prima. Ad ogni iterazione, controllo il nome dell'elemento su cui mi trovo. Quando il nome del tag è "year", allora posso leggere il contenuto del tag direttamente castandolo ad intero. Esiste un metodo ReadElementContentAs per ogni tipo di dato, ovviamente. Possiamo eventualmente usare il metodo <a title="ReadElementContentAs" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.readelementcontentas.aspx">ReadElementContentAs</a>&nbsp;per leggere il contenuto di un tag specificando il Type corretto.</p> <p>Al di là dello spostarsi nel documento con il metodo <strong>Read</strong>, possiamo utilizzare altri metodi più efficaci e più specifici in base al contesto. Se un certo elemento ha uno o più attributi, possiamo usare <a title="MoveToFirstAttribute" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.movetofirstattribute.aspx">MoveToFirstAttribute</a>&nbsp;e <a title="MoveToNextAttribute" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.movetonextattribute.aspx">MoveToNextAttribute</a>. Non hanno bisogno di parametri, ritornano <font color="#0000ff">true</font> se l'operazione ha avuto successo, altrimenti <font color="#0000ff">false</font>. Il metodo <a title="MoveToAttribute" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.movetoattribute.aspx">MoveToAttribute</a>&nbsp;è un po' più selettivo: come parametri accetta in input un <a href="http://msdn2.microsoft.com/en-us/library/k64ft7tb.aspx" target="_blank">Int32</a> o una <a href="http://msdn2.microsoft.com/en-us/library/t4323tz2.aspx" target="_blank">string</a>&nbsp;per indicare a quale attributo spostarsi.</p> <p>Se volete skippare tutti i nodi fino a quando non ne trovate uno con un particolare tag, utilizzate il metodo <a title="XmlReader.ReadToFollowing (String)" href="http://msdn2.microsoft.com/en-us/library/ms162536.aspx">ReadToFollowing</a>&nbsp;che accetta una stringa che fa avanzare l'XmlReader fino al punto desiderato. Se volete skippare tutti i nodi fino al nodo "fratello" di quello corrente (un altro nodo alla stessa profondità con lo stesso nome di tag) utilizzate il metodo <a title="ReadToNextSibling" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlreader.readtonextsibling.aspx">ReadToNextSibling</a>.</p> <p>La classe <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnodereader_members.aspx" target="_blank">XmlNodeReader</a>&nbsp;è una classe derivata da XmlReader, che ne specializza il comportamento permettendo la navigazione di un singolo nodo (<a title="XmlNode" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.aspx">XmlNode</a>).</p><img src="http://blogs.ugidotnet.org/idamiani/aggbug/65780.aspx" width="1" height="1" /> Igor Damiani http://blogs.ugidotnet.org/idamiani/archive/2007/01/10/65780.aspx Wed, 10 Jan 2007 17:01:00 GMT http://blogs.ugidotnet.org/idamiani/archive/2007/01/10/65780.aspx#feedback http://blogs.ugidotnet.org/idamiani/comments/commentRss/65780.aspx http://blogs.ugidotnet.org/idamiani/services/trackbacks/65780.aspx [70-526, #3] Altri dettagli sulla gestione dei documenti XML http://blogs.ugidotnet.org/idamiani/archive/2007/01/10/65704.aspx <p>Vediamo nel dettaglio altri aspetti del DOM del .NET Framework che ci permettono di lavorare sui nodi di un documento XML. La classe XmlDocument espone una serie di metodi riconoscibili&nbsp;dal prefisso <strong>Create</strong>, che consentono di creare nuovi attributi (<a title="CreateAttribute" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.createattribute.aspx">CreateAttribute</a>), commenti (<a title="CreateComment" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.createcomment.aspx">CreateComment</a>), elementi (<a title="CreateElement" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.createelement.aspx">CreateElement</a>), nodi (<a title="CreateNode" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.createnode.aspx">CreateNode</a>) e quant'altro.</p> <p></p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:9471cf39-23d4-48e0-aad2-e4adb0fc0d8e" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #000000; ">XmlNodeList listNodes </span><span style="color: #000000; ">=</span><span style="color: #000000; "> _doc.GetElementsByTagName(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">book</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">); XmlNode nodoTrovato </span><span style="color: #000000; ">=</span><span style="color: #000000; "> listNodes[</span><span style="color: #000000; ">0</span><span style="color: #000000; ">]; XmlAttribute newAttribute </span><span style="color: #000000; ">=</span><span style="color: #000000; "> _doc.CreateAttribute(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">id</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">); newAttribute.InnerText </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">; nodoTrovato.Attributes.Append(newAttribute);</span></div></pre></div> <p></p> <p>Il codice qui sopra recupera tutti gli XmlNode chiamati <strong>book</strong> e prende il primo. Poi crea un nuovo attributo - notare che il costruttore di <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlattribute.aspx" target="_blank">XmlAttribute</a> prende il nome dell'attributo stesso - gli&nbsp;assegna un valore importantissimo, "1" ;-), e lo aggiunge al nodo&nbsp;di cui abbiamo ottenuto il riferimento&nbsp;prima. Se salvassimo su file con il metodo&nbsp;<a title="Save" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.save.aspx">Save</a> vedremmo:</p> <p></p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:584ea50e-bf63-4c72-8a26-1ac74cbdaa4c" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">book id</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "> </span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">author</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">Terry Brooks</span><span style="color: #000000; ">&lt;/</span><span style="color: #000000; ">author</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "> </span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">title</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">La Spada di Shannara</span><span style="color: #000000; ">&lt;/</span><span style="color: #000000; ">title</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "> </span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">pages</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">450</span><span style="color: #000000; ">&lt;/</span><span style="color: #000000; ">pages</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "> </span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">year</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">1998</span><span style="color: #000000; ">&lt;/</span><span style="color: #000000; ">year</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "> </span><span style="color: #000000; ">&lt;/</span><span style="color: #000000; ">book</span><span style="color: #000000; ">&gt;</span></div></pre></div> <p></p> <p>Possiamo clonare un XmlNode con la chiamata al metodo <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.clonenode.aspx" target="_blank">CloneNode</a>. Per esempio, sempre tenendo presente le righe di codice scritte sopra, possiamo clonare l'oggetto <em>nodoTrovato</em> ed ottenere <em>nodoClonato</em>. Questo metodo accetta un parametro <strong>bool</strong> che esprime se la clonazione deve avvenire anche per tutti&nbsp;gli eventuali&nbsp;child nodes dell'XmlNode che stiamo clonando. Possiamo quindi indicare true o false a seconda di quello che ci serve. Il metodo ritorna un altro oggetto XmlNode che va inserito nell'XmlDocument dove ci serve. Per esempio:</p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:f9d789e2-7858-4c40-bc01-a1f6a0174a85" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #008000; ">//</span><span style="color: #008000; "> Aggiunge nodoClonato in fondo, dopo tutti i &lt;book&gt;</span><span style="color: #008000; "> </span><span style="color: #000000; ">_doc.ChildNodes[</span><span style="color: #000000; ">0</span><span style="color: #000000; ">].AppendChild(nodoClonato); </span><span style="color: #008000; ">//</span><span style="color: #008000; "> Aggiunge nodoClonato prima di tutti i &lt;book&gt;</span><span style="color: #008000; "> </span><span style="color: #000000; ">_doc.FirstChild.PrependChild(nodoClonato);</span></div></pre></div> <p><a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.appendchild.aspx" target="_blank">AppendChild</a> e <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.prependchild.aspx" target="_blank">PrependChild</a> (di cui parlava <a href="http://blogs.ugidotnet.org/odamiani" target="_blank">mio fratello</a> nel mio ultimo post) sono due metodi che inseriscono XmlNode in ultima ed in prima posizione rispetto ai child nodes dell'XmlNode su cui stiamo effettuando l'operazione.</p><img src="http://blogs.ugidotnet.org/idamiani/aggbug/65704.aspx" width="1" height="1" /> Igor Damiani http://blogs.ugidotnet.org/idamiani/archive/2007/01/10/65704.aspx Wed, 10 Jan 2007 11:09:00 GMT http://blogs.ugidotnet.org/idamiani/archive/2007/01/10/65704.aspx#feedback 1 http://blogs.ugidotnet.org/idamiani/comments/commentRss/65704.aspx http://blogs.ugidotnet.org/idamiani/services/trackbacks/65704.aspx [70-526, #2] Manage XML with XML Document Object Model http://blogs.ugidotnet.org/idamiani/archive/2007/01/09/65609.aspx <p>Un documento XML viene rappresentato in memoria attraverso la classe <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=XmlDocument+Class+(System.Xml)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.aspx" target="_blank">XmlDocument</a>. Tutti gli oggetti .NET che hanno a che fare con il trattamento di documenti XML sono contenuti all'interno del namespace <a href="http://msdn2.microsoft.com/en-us/library/system.xml.aspx" target="_blank">System.Xml</a>. Non so il perchè, ma tutte le volte che devo caricare un documento XML sono convinto di usare il metodo Load come se fosse statico, mentre è di istanza: quando me lo ricorderò, sarà ormai troppo tardi! :-) Abbiamo due strade: una prevede l'utilizzo del metodo <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.load.aspx" target="_blank">Load</a>, l'altra il metodo <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.loadxml.aspx" target="_blank">LoadXml</a>.</p> <p>Con quest'ultimo metodo possiamo caricare un documento XML direttamente da una stringa, come qui sotto:</p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:052d5395-10d0-4900-92eb-9071a74bcd1a" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #000000; ">StringBuilder bld </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> StringBuilder(); bld.AppendLine(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">&lt;books&gt;</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">); bld.AppendLine(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">&lt;book&gt;</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">); bld.AppendLine(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">&lt;author&gt;Terry Brooks&lt;/author&gt;</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">); bld.AppendLine(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">&lt;title&gt;Le Pietre Magiche&lt;/title&gt;</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">); bld.AppendLine(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">&lt;pages&gt;450&lt;/pages&gt;</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">); bld.AppendLine(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">&lt;year&gt;1998&lt;/year&gt;</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">); bld.AppendLine(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">&lt;/book&gt;</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">); bld.AppendLine(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">&lt;/books&gt;</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">); </span><span style="color: #0000FF; ">string</span><span style="color: #000000; "> xml </span><span style="color: #000000; ">=</span><span style="color: #000000; "> bld.ToString(); XmlDocument doc </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> XmlDocument(); doc.LoadXml(xml);</span></div></pre></div> <p>Usando uno <strong>StringBuilder</strong> costruisco un documento XML minimale, ma tecnicamente valido. Usando <strong>LoadXml</strong>, carichiamo la stringa in un XmlDocument. Se il documento XML non dovesse essere well-formed, il framework solleva l'exception <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlexception.aspx" target="_blank">XmlException</a>. Il metodo <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.load.aspx" target="_blank">Load</a> invece carica l'XML da un file fisico su disco, da uno Stream, da un TextReader o da un XmlReader.</p> <p>Una volte che il documento è stato caricato in memoria, il FW ci mette a disposizione tutta una serie di metodi che ci permettono di navigare il documento o di ricercare informazioni al suo interno. Il metodo <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.getelementsbytagname.aspx" target="_blank">GetElementsByTagName</a> ci ritorna un'istanza di <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnodelist.aspx" target="_blank">XmlNodeList</a> che contiene l'elenco di tutti i tag XML con un certo nome, specificato nella chiamata.</p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:311340be-20cd-46c1-8c90-3616c767dc48" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #000000; ">XmlNodeList nodes </span><span style="color: #000000; ">=</span><span style="color: #000000; "> doc.GetElementsByTagName(</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">book</span><span style="color: #000000; ">&quot;</span><span style="color: #000000; ">);</span></div></pre></div> <p>In questo caso, l'oggetto <strong>nodes</strong> contiene in questo caso un solo oggetto <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.aspx" target="_blank">XmlNode</a>. Se vogliamo fare ricerche un po' più complesse usando XPath, abbiamo due metodi: <a title="SelectNodes" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.selectnodes.aspx">SelectNodes</a>&nbsp;(che ritorna un XmlNodeList che contiene i nodi che soddisfano i criteri di ricerca espressi in XPath) e <a title="SelectSingleNode" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.selectsinglenode.aspx">SelectSingleNode</a>&nbsp;(che invece ritorna il primo XmlNode trovato). XmlDocument espone le proprietà <a title="FirstChild" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.firstchild.aspx">FirstChild</a>&nbsp;e <a title="LastChild" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.lastchild.aspx">LastChild</a>&nbsp;che ritornano rispettivamente il primo e l'ultimo XmlNode presente nel documento caricato. La proprietà <a title="ParentNode" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.parentnode.aspx">ParentNode</a>&nbsp;permette di ottenere l'istanza di XmlNode padre rispetto a quella corrente. La proprietà <a title="NextSibling" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.nextsibling.aspx">NextSibling</a>&nbsp;ritorna un XmlNode che è il "fratello" successivo dell'XmlNode corrente, mentre <a title="PreviousSibling" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.previoussibling.aspx">PreviousSibling</a>&nbsp;percorre l'XML in senso opposto. Se avessi tanti &lt;book&gt; inseriti nel blocco XML sopra, potrei saltare da uno all'altro semplicemente 1) ottenendo un riferimento XmlNode al primo &lt;book&gt; inserito nel documento e 2) chiamando NextSibling per balzare da uno all'altro.</p> <p>Ovviamente, ci sono tutta una serie di funzionalità anche per modificare il documento, aggiungendo e rimuovendo XmlNode dove necessario. <a title="AppendChild" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.appendchild.aspx">AppendChild</a>, <a title="CreateNode" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.createnode.aspx">CreateNode</a>, <a title="ImportNode" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmldocument.importnode.aspx">ImportNode</a>&nbsp;(per importare XmlNode da un documento all'altro), <a title="InsertAfter" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.insertafter.aspx">InsertAfter</a>, <a title="InsertBefore" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.insertbefore.aspx">InsertBefore</a>&nbsp;sono alcuni dei metodi esposti da XmlDocument. <a title="RemoveAll" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.removeall.aspx">RemoveAll</a>, <a title="RemoveChild" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.removechild.aspx">RemoveChild</a>&nbsp;e <a title="ReplaceChild" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode.replacechild.aspx">ReplaceChild</a>&nbsp;sono piuttosto auto-esplicativi.</p> <p>L'oggetto <strong>XmlDocument</strong> eredita da <strong>XmlNode</strong>. Effettivamente, ne condivide buona parte dell'interfaccia. Basta dare un'occhiata <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnode_members.aspx" target="_blank">ai membri esposti</a> da XmlNode per farsene un'idea. La prima cosa che salta all'occhio è che XmlNode non&nbsp;espone eventi, mentre XmlDocument sì: se volessi monitorare in qualche modo tutto quello che accade ad un certo nodo XML (modifiche al suo InnerText, per esempio), quindi, non posso sottoscrivere un evento specificatamente per quel nodo, ma quelli relativi all'intero documento. Il FW2.0 ci permette di gestire&nbsp;una piccolo&nbsp;set di eventi relativi ai nodi XML: <a href="http://msdn2.microsoft.com/en-us/library/80x630zd.aspx" target="_blank">li potete vedere elencati qui</a>&nbsp;(cancellazione, inserimento e modifiche ai nodi del documento). Gli event handler fanno uso della classe <a title="XmlNodeChangedEventArgs" href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnodechangedeventargs.aspx">XmlNodeChangedEventArgs</a>&nbsp;che espone <a href="http://msdn2.microsoft.com/en-us/library/system.xml.xmlnodechangedeventargs_members.aspx" target="_blank">una serie di membri</a> per capire esattamente cosa è successo e dove.</p><img src="http://blogs.ugidotnet.org/idamiani/aggbug/65609.aspx" width="1" height="1" /> Igor Damiani http://blogs.ugidotnet.org/idamiani/archive/2007/01/09/65609.aspx Tue, 09 Jan 2007 13:12:00 GMT http://blogs.ugidotnet.org/idamiani/archive/2007/01/09/65609.aspx#feedback 1 http://blogs.ugidotnet.org/idamiani/comments/commentRss/65609.aspx http://blogs.ugidotnet.org/idamiani/services/trackbacks/65609.aspx [70-526, #1] Create event handlers for Windows Forms and controls http://blogs.ugidotnet.org/idamiani/archive/2007/01/08/65492.aspx <p>In questo <a href="http://blogs.ugidotnet.org/idamiani/archive/2005/07/06/22268.aspx" target="_blank">antico post</a>, descrivevo come gestire e creare event handler con il framework 1.1. Con il FW2.0 nulla è cambiato: tutti gli oggetti hanno un certo numero di eventi, a ciascuno dei quali possiamo associare un handler, ovvero un metodo privato che viene eseguito quando quell'evento viene sollevato dal CLR. Per esplorare gli eventi esposti da un certo oggetto posto su una Windows Forms, è sufficiente selezionare l'oggetto a design-time, aprire la <strong>Properties Windows</strong> e cliccare sull'icona del lampo.</p> <p>Il tipo ed il numero di eventi dipende ovviamente dall'oggetto con cui abbiamo a che fare. Per creare un event handler, è sufficiente fare doppio-click sull'evento che ci interessa gestire. Per esempio,&nbsp;possiamo&nbsp;scrivere codice per&nbsp;l'evento <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.form.formclosing.aspx" target="_blank"><strong>FormClosing</strong></a> su una WF semplicemente facendo doppio-click sulla riga nella Properties Windows. Il designer di VS2005 ci porta direttamente nell'editor di codice:</p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:b48221a6-9531-489c-a58b-c1db45d5bb4e" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #0000FF; ">private</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">void</span><span style="color: #000000; "> FormEventHandler_FormClosing(</span><span style="color: #0000FF; ">object</span><span style="color: #000000; "> sender, FormClosingEventArgs e) { }</span></div></pre></div> <p>Ogni event handler è come al solito due parametri. Uno è il <strong>sender</strong>, che identifica l'oggetto che ha sollevato l'evento: è di tipo object, ovviamente. Il secondo parametro dipende dall'evento. In questo caso è di tipo <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=FormClosingEventArgs+Class+(System.Windows.Forms)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.windows.forms.formclosingeventargs.aspx" target="_blank"><strong>FormClosingEventArgs</strong></a>, una classe che ci permette per esempio di annullarne la chiusura o capire chi stava chiudendo e perchè il form stava per essere chiuso.</p> <p>L'esame 70-526 ci chiede due cose in particolare: <em><font color="#0000ff">use the Windows Forms designer to create event handler</font></em>. Ed è quello di cui ho parlato qui sopra, ovvero saper esplorare nella Properties Windows l'evento che ci interessa e fare doppio-click. L'altra è <em><font color="#0000ff">use the Windows Forms designer to create default event handler</font></em>. Questo può essere fatto molto semplicemente facendo doppio-click sull'oggetto della WF. Ogni controllo&nbsp;ha un default event handler, che banalmente può essere descritto come l'evento di più frequente utilizzo (ad esempio, il Click su un Button). Quando sviluppiamo nostri controlli, possiamo utilizzare l'attributo <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=DefaultEventAttribute+Class+(System.ComponentModel)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.componentmodel.defaulteventattribute.aspx" target="_blank"><strong>DefaultEventAttribute</strong></a> proprio a questo scopo.</p> <p>Un'altra questione importante: <em><font color="#0000ff">connect multiple events to a single event handler</font></em>. Detto in altri termini: avere un'unica routine .NET capace di rispondere a più eventi diversi. Per far questo, è ovviamente necessario che la firma della routine sia la stessa. Questa tecnica ci permette di avere un certo numero di Button sulla WF il cui event handler sull'evento Click sia lo stesso, risparmiando così codice e codice da scrivere e da debuggare. Il parametro sender di cui ho parlato prima serve proprio per questo, ovvero a discriminare quale oggetto ha sollevato l'evento. Questo può essere ottenuto anche da IDE, perchè la Properties Windows è sensibile: non solo possiamo creare nuovi event handler, ma possiamo eventualmente selezionare dalla ComboBox la routine già esistente nel codice e che si adatta a gestire l'evento correntemente selezionato.</p> <p>Come avevo già detto l'anno scorso, gli eventi vengono sottoscritti al loro event handler con una semplice linea di codice, che finisce nel <em>FormName</em>.Designer.cs. Nel caso dell'evento FormClosing, avremo quindi:</p> <div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:7e20d40d-fd3c-421c-bc31-d4d5c0d49e16" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.FormClosing </span><span style="color: #000000; ">+=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> FormClosingEventHandler(</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.FormEventHandler_FormClosing);</span></div></pre></div> <p>Questo codice è inserito nella InitializeComponent() della WF su cui stiamo lavorando. Possiamo ovviamente ottenere lo stesso risultato senza usare il designer di VS2005: se facciamo un cut &amp; paste nell'evento Load della WF otteniamo esattemente lo stesso risultato. Questo è di fondamentale importanza quando vengono creati ed aggiunti nuovi controlli a run-time sulla WF, un po' come succede con <a href="http://www.codeplex.com/HappySign" target="_blank">Happy Sign</a>, dove ogni volta che si aggiunge una firma vengono associati gli event handler necessari.</p> <p>Per la questione <em><font color="#0000ff">use the code editor to override methods defined in the base class</font></em> è tutto molto semplice. Dall'editor di VS2005, possiamo cominciare a scrivere un nuovo metodo usando la keyword <strong>override</strong>. L'Intellisense - che tanto stupido non è - mostra un elenco di tutti quei membri (properties, indexers e events) della classe base che <strong>possiamo ridefinire</strong>. Ciò implica diverse cose: il metodo della classe base può essere ridefinito se è stato definito <strong>virtual</strong>:&nbsp;per default, in C# i metodi non sono virtuali. Ciò significa che non possiamo ridefinire tutto ciò che vogliamo. Vi consiglio la lettura <a href="http://msdn2.microsoft.com/en-us/library/6fawty39(VS.80).aspx" target="_blank">di questa pagina</a> di MSDN che descrive bene tutte le implicazioni di <strong>virtual</strong>, <strong>new</strong> ed&nbsp;<strong>override</strong>. Se è vero che possiamo ridefinire il comportamento di un evento, possiamo comunque chiamare il metodo della classe base attraverso l'utilizzo della keyword <strong>base</strong>.</p> <p>Gli ultimi due punti per questa parte dell'esame - davvero molto semplice, devo dire - riguardano <em><font color="#0000ff">manage mouse and keyboard events within Windows Forms applications</font></em>. E' possibile avere una carrellata degli eventi disponibili guardando la Properties Window nella modalità Categorized. Il gruppo Key contiene 4 eventi per la tastiera (KeyDown, KeyPress, KeyUp e PreviewKeyDown), mentre il gruppo Mouse contiene 6 eventi per il mouse (MouseDown, MouseEnter, MouseHover, MouseLeave, MouseMove e MouseUp). Non sto a mettervi il link per ogni evento, vi lascio questo che elenca <a href="http://msdn2.microsoft.com/en-us/library/1dk48x94.aspx" target="_blank">tutti gli eventi esposti dalla classe Control</a>. A seconda dell'evento che decidiamo di usare, abbiamo diverse opzioni. Le elenco in breve.</p> <p>L'evento MouseDown (così come MouseMove e MouseUp) fa uso della classe <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=MouseEventArgs+Class+(System.Windows.Forms)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.windows.forms.mouseeventargs.aspx" target="_blank">MouseEventArgs</a>, che espone tra le altre cose la proprietà Button, che ci permette di capire quale bottone del mouse è stato cliccato. La stessa filosofia la si applica con la tastiera: a seconda dell'evento, possiamo capire quale tasto è stato premuto e se insieme a lui è stato premuto qualche tasto come CTRL, ALT o SHIFT (vedere la classe <a href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=KeyEventArgs+Class+(System.Windows.Forms)+&amp;url=http://msdn2.microsoft.com/en-us/library/system.windows.forms.keyeventargs.aspx" target="_blank">KeyEventArgs</a> per maggiori informazioni). Questo può essere fatto in due modi: usando le proprietà read-only esposte da KeyEventArgs (<strong>Alt</strong>, <strong>Control</strong> e <strong>Shift</strong>) oppure leggendo il valore della proprietà <a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.keyeventargs.modifiers.aspx" target="_blank"><strong>Modifiers</strong></a>.</p><img src="http://blogs.ugidotnet.org/idamiani/aggbug/65492.aspx" width="1" height="1" /> Igor Damiani http://blogs.ugidotnet.org/idamiani/archive/2007/01/08/65492.aspx Mon, 08 Jan 2007 15:14:00 GMT http://blogs.ugidotnet.org/idamiani/archive/2007/01/08/65492.aspx#feedback 1 http://blogs.ugidotnet.org/idamiani/comments/commentRss/65492.aspx http://blogs.ugidotnet.org/idamiani/services/trackbacks/65492.aspx