Esce questa settimana il numero 4000 della Settimana Enigmistica, il miglior settimanale italiano. Di cuore, buon anniversario :-)

L’object model di ADO.NET puo’ essere suddiviso in: data-related components/content components (DataSet e suoi derivati, quali DataTable, DataView, ecc) e data-provider components (Connection, Command, DataReader, ecc).

Il datareader fornisce un accesso ai dati forward-only, read-only, simile al vecchio ADO Recordset.
Il dataset e’ analogo a una cache di un subset di database che puo’ essere usato per operazioni disconnesse.

Il DataAdapter permette di leggere il contenuto da una fonte dati e di inviare al datasource i cambiamenti operati nel DataSet.

I vantaggi di ADO.NET sono:

Interoperabilita: l’uso di XML come formato di dati su HTTP minimizza i problemi di firewall ed e’ sufficiente un parser xml per interpretare i dati.

Scalabilita: in una architettura client/server e’ tipico stabilire una connessione e non lasciarla fino al termine dell’operazione; questo, al crescere della complessita’ delle architetture, comporta un dispendio di CPU e di risorse di rete. Con l’uso di dataset disconnessi, viene bypassato questo problema. Quando un client richiede dei dati, si connettte, li ottiene e chiude la connessione appena possibile, risolvendo il problema delle connessioni limitate.
Visto che in certi contesti l’operazione di connessione e’ molto pesante, si potrebbe pensare che aprire e chiudere la connessione non sia una grande idea, ma questo varrebbe se non ci fosse il connection pooling; ado.net mantiene le connessioni a un datasource in un pool, cosi’ che quando una app ne chiude una, questa non viene distrutta ma inserita nel pool pronta per essere recuperata successivamente senza la necessita’ di essere creata da zero.

Performance: i dataset disconnessi e il connection pooling velocizzano moltissimo le opeazioni e, visto che le info sono in xml non servono nepppure conversioni da tipi di dati particolari, come avveniva con COM. Esistono poi data provider ottimizzati per diversi tipi di DB, in modo che possano dialogare direttamente con il db server, ad es. il Data Provider per SqlServer.

CONTENT COMPONENTS

I cc incapsulano dati;

DataSet

In ADO, i dati erano trasferiti in RecordSet, che contiene dati in forma tabellare; anche se provenienti da piu’ tabelle, i dati arrivano joined come se arrivassero da una tabella unica; nel dataset e’ aggiunta una dimensione consentendo l’arrivo di piu’ recordset insieme. Puo’ essere visto come una vista in memoria del database che contiene piu’ DataTable e DataRelations.

Ma come avviene la sincronizzazione dei dati quando il DS e’ disconnesso?? In qualche modo lui stesso deve tenere traccia dei cambiamenti operati su di se’, infatti esistono metodi e proprieta (anche invocabili da noi) come HasChanges(), HasErrors, GetChanges(), AcceptChanges(), RejectChanges(); per attivare le modifiche esiste il metodo Update del DS.

Il DataSet ha 2 importanti collezioni: Tables (di tipo DataTableCollection) e Relations (di tipo DataTableRelations):

DataSet
   DataTableCollection
      DataTable
         DataRowCollection
            DataRow
         DataColumnCollection
            DataColumn
         DataView
   DataRelationCollection
       DataRelation

Esempione:

DataSet ds = new DataSet("ds_squadre");
ds.Tables.Add("squadre");
ds.Tables["squadre"].Columns.Add(”id_squadra”);
ds.Tables["squadre"].Columns.Add(”ds_squadra”);
ds.Tables["squadre"].Columns.Add(”valore_squadra”);
DataRow dr;
dr = ds.Tables["squadre"].NewRow();
dr["id_squadra"] = 1;
dr["ds_squadra"] = “Juve”;
dr["valore_squadra"] = 9;
ds.Tables["squadre"].Rows.Add(dr);
dr = ds.Tables["squadre"].NewRow();
dr["id_squadra"] = 2;
dr["ds_squadra"] = “Inter”;
dr["valore_squadra"] = 1;
ds.Tables["squadre"].Rows.Add(dr);
ds.WriteXml(Console.Out);
ds.AcceptChanges(); //commmit, da ora in poi controlla cambiamenti
ds.Tables["squadre"].Rows[1]["valore_squadra"] = 0;
if (ds.HasChanges())
{
DataSet changeDS = ds.GetChanges();
Console.WriteLine(”DIFFERENCES”);
changeDS.WriteXml(Console.Out, XmlWriteMode.DiffGram);
ds.AcceptChanges();
Console.WriteLine(”FINAL SITUATION”);
ds.WriteXml(Console.Out);
}

L’output risultante e’ questo:

Data providers

Connection: a differenza della Connection ADO, il supporto per le transazioni e’ stato spostato su uno specifico oggetto Transaction perche’ non si poteva asssumere che tutti i data providers garantissero lo stesso supporto per le transazioni. Non e’ altresi’ presente nessun metodo Execute, ora demandato in modo piui’ pulito all’oggetto Command, insomma la Connection fa la connection….

Command: l’oggetto Command, tramite la prop Connection e’ associato a una connessione. Il Command e’ l’unico modo per fare insert/update/delete da ADO.NET. Ci sono 2 tipi di esecuzione: la query, tramite il metodo ExecuteQuery e l’esecuzione di ins/upd/del, tramite ExecuteNonQuery. A differenza di ADO, cio’ che viene restituito da Command non e’ un RecordSet ma un DataReader.

DataReader: consente di accedere ai records in forward-only e read-only e di loopare tramite il metodo Read()

Data Adapter: agisce da bridge tra il datasource e il dataset disconnesso. Esso contiene una Connection e una serie di Command per prelevare i dati e metterli in una DataTable nel DataSet e modificarli nel Datasource quando cambiano nel DataSet. Il metodo Fill del DataAdapter riempie un DataSet in base al comando associato e il metodo Update() invia le modifiche fatte sul DataSet verso il DataSource.

Credo che la versone 2.0.0.18 abbia qualche problema di incompatibilita’ con librerie tipo jQuery. La Facebox infatti non funziona piu’ e anche su Facebook molte funzionalita’ web 2.0 tipo l’open/close dei div non vanno. Sono tornato alla 2.0.0.17, stavolta numero fortunato, e ho modificato in manuale l’aggiornamento automatico, in attesa di una 2.0.0.19 piu’ sana.

Prima del .NET 3.0 le Web apps erano scritte con markup langs, mentre le Win Apps non potevano esserlo. Il FW 3.0 ha cambiato questa situazione introducendo lo XAML (pron. zzzzzamel), eXtensible Application Markup Language, che ha 2 caratteristiche fondamentali:

1) E’ un linguaggio di markup (come l’html) per creare Win Apps
2) Quasi tutti gli oggetti XAML hanno un oggetto corrispondende nel CLR; la maggior parte di cio’ che si crea con XAML puo’ essere creato con programmi C#/VB.NET

Per fare un esempio:

<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Label Content="Hello Cris" FontFamily="Tahoma" FontSize="24"></Label>
</Grid>
</Window>

Il tag <Label/> equivale a System.Windows.Control con tutte le sue proprieta’ e i suoi metodi.

I files xaml, in qualita’ di xml, devono essere ben formati, quindi occorre seguire le regole di Case, di Quotes e quant’altro.

Control Elements

I controls possono essere classificati in:

  • Simple controls - non hanno le proprieta’ Content, Header e Item. Es. Image, Frame
  • Content controls - hanno la proprieta Content e possono quindi contenere anche oggetti al loro interno (es Button, TextBox)
  • Item controls - contengono al loro interno una collezione di controls
  • Header item controls - non hanno l’attributo Content ma hanno l’attributo Header (es. MenuItem)
  • Headered content controls - possono avere il Content e l’header, ma non Item (cioe’ solo un livello di contenuto, ad es. l’Expander)

Document elements

Una caratteristica innovativa di XAML e’ la possibilita di visualizzare i documenti, oltre che col classico FixedDocument, con il FlowdDocument, come nell’esempio che segue:

<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<FlowDocument>
<Paragraph>Paragrafo 1</Paragraph>
<Paragraph>Paragrafo 2</Paragraph>
<Paragraph>Paragrafo 3</Paragraph>
<Paragraph>Paragrafo 4</Paragraph>
<Paragraph>Paragrafo 5</Paragraph>
<Paragraph>Paragrafo 6</Paragraph>
<Paragraph>Paragrafo 7</Paragraph>
<Paragraph>Paragrafo 8</Paragraph>
<Paragraph>Paragrafo 9</Paragraph>
<Paragraph>Paragrafo 10</Paragraph>
</FlowDocument>
</Window>

L’output e’ comodissimo e apre la porta a molte possibilita’ di impaginazione:

ma anche:

Questa magia accade grazie al fatto che XAML, in qualita’ di parte di WPF, riesce ad aggiustare e raggruppare le pagine in base alla risoluzione dello schermo.

Quando si deve disegnare una semplice interfaccia, si possono utilizzare diverse sottoclassi di Panel: DockPanel, StackPanel o Grid (forse per cose piu’ complesse); lo scopo di questi elementi e’ favorire e gestire la posizione degli altri oggetti sullo schermo.

Il DockPanel permette di attaccare quelli che in html sono dei div in modo da realizzare facilmente una classica struttura header, menu left e main:

<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">

<DockPanel>
<Border Height=”70″ Width=”300″ DockPanel.Dock=”top” HorizontalAlignment=”Center”
BorderBrush=”YellowGreen” BorderThickness=”1″>
<Label Content=”Top banner” FontSize=”32″></Label>
</Border>
<Border Height=”220″ Width=”100″ DockPanel.Dock=”Left” BorderBrush=”RosyBrown” BorderThickness=”1″>
<Label Content=”Left side” FontSize=”14″></Label>
</Border>
<Border Height=”220″ Width=”200″ DockPanel.Dock=”Left” BorderBrush=”LavenderBlush” BorderThickness=”1″>
<Label Content=”Right side” FontSize=”14″></Label>
</Border>
</DockPanel>
</Window>
Che produce:

La Grid

Il Panel piu’ flessibile e’ senz’altro la Grid, che analogamente alla table html da’ pieno controllo su righe e colonne:


<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock FontSize="36" Foreground="white" Background="Blue" Grid.Column="0" Grid.Row="0" Text="1"></TextBlock>
<TextBlock FontSize="36" Background="Gold" Grid.Column="1" Grid.Row="0" Text="2"></TextBlock>
<TextBlock FontSize="36" Foreground="white" Background="Crimson" Grid.Column="2" Grid.Row="0" Text="3"></TextBlock>
<TextBlock FontSize="36" Background="White" Grid.Column="0" Grid.Row="1" Text="4"></TextBlock>
<TextBlock FontSize="36" Foreground="White" Background="Purple" Grid.Column="1" Grid.Row="1" Text="5"></TextBlock>
<TextBlock FontSize="36" Foreground="white" Background="Green" Grid.Column="2" Grid.Row="1" Text="6"></TextBlock>
<TextBlock FontSize="36" Background="AliceBlue" Grid.Column="0" Grid.Row="2" Text="7"></TextBlock>
<TextBlock FontSize="36" Foreground="Black" Background="Bisque" Grid.Column="1" Grid.Row="2" Text="8"></TextBlock>
<TextBlock FontSize="36" Foreground="white" Background="DarkOrange" Grid.Column="2" Grid.Row="2" Text="9"></TextBlock>
</Grid>
</Window>

Produce:

Effetti carini
Gradiente:

<Window.Resources>
<LinearGradientBrush x:Key="ButtonGradient">
<GradientStop Color="Red" Offset="0"></GradientStop>
<GradientStop Color="LimeGreen" Offset="0.8"></GradientStop>
</LinearGradientBrush>
</Window.Resources>
<Button Background="{DynamicResource ButtonGradient}" Width="150" Height="40"></Button>

Rotazione di oggetti:

<StackPanel>
<Button Content="Press me" Background="LimeGreen" Foreground="White" Width="100">
</Button>
<Button Content="i'm rotated" Background="Beige" Foreground="White" Width="100">
<Button.RenderTransform>
<RotateTransform Angle="30"></RotateTransform>
</Button.RenderTransform>
</Button>
<Button Content="me too" Background="DarkRed" Foreground="White" Width="100">
<Button.RenderTransform>
<RotateTransform Angle="60"></RotateTransform>
</Button.RenderTransform>
</Button>

</StackPanel>

Basandomi su un tutorial di Scott Gu, provo a realizzare una app in SL in grado di interrogare un web service pubblico e poi a visualizzare il risultato in modo carino.

Last.fm e’ la famosa community musicale tramite cui ognuno puo’ crearsi un profilo in base ai propri gusti musicali e interagire con gli altri … bla bla … insomma un perfetto esempio di applicazione web 2.0; tra le altre cose espone le proprie API come web services e utilizzero’ proprio una chiamata al loro web service per visualizzare quelli che sono i miei brani preferiti, invocando il metodo library.gettracks a cui appendo il mio username: http://ws.audioscrobbler.com/2.0/?method=library.gettracks
&api_key=b25b959554ed76058ac220b7b2e0a026&user=cdiscla

Nel mio progetto SL in C# creo una class contenente i campi che voglio prendere dal WS e visualizzare nella mia app SL.

namespace WS_LastFM_SLight
{
public class lastFM
{
public string name { get; set; }
public string url {get;set;}
public string image { get; set; }
public string author { get; set; }
public int playcount { get; set; }
}
}

All’avvio dell’applicazione SL richiamo il Web Service di last.fm:

string sWSUrl = “http://ws.audioscrobbler.com/2.0/?method=library.gettracks&api_key=b25b959554ed76058ac220b7b2e0a026&user=cdiscla”;
WebClient wsFM = new WebClient();
wsFM.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wsFM_DownloadCompleted);
wsFM.DownloadStringAsync(new Uri(sWSUrl));

Nella gestione dell’evento DownloadStringCompletedEventHandler avviene l’intervento di Linq:

private void wsFM_DownloadCompleted(System.Object sender, DownloadStringCompletedEventArgs e)
{
  if(e.Error==null)
  {
    string result=e.Result;
    DisplayTracks(result);
  }
}

private void DisplayTracks(string sTracks)
{
  XDocument xmlTracks = XDocument.Parse(sTracks);
  //
  var t = from track in xmlTracks.Descendants("track")
    where track.Element("image")!=null &&
                 track.Element("image").Attribute("size").Value.Equals("small")
    select new lastFM
    {
      name=((string)track.Element("name").Value).Trim(),
      url = ((string)track.Element("url").Value).Trim(),
      image = ((string)track.Element("image").Value),
      playcount= (Convert.ToInt16(track.Element("playcount").Value)),
      author=((string)track.Element("artist").Element("name").Value)
    };
    lastFMGrid.ItemsSource = t;
}

Il risultato puo’ essere visualizzato qui

I sorgenti, invece, sono qui.

Il fatto e’ che il tutto non e’ propriamente bello da vedere, nel prossimo articolo su SL cerchero’ di aggiustarlo esteticamente.

Una caratteristica importante degli operatori Linq e’ l’esecuzione differita. Cio’ consiste nel fatto che vengono eseguiti NON durante la loro costruzione ma quando vengono enumerati (cioe’ quando nell’enumeratore viene richiamato il metodo MoveNext).

Nel seguente esempio:

var nomi = new List<String>();
nomi.Add("Cristina");
IEnumerable<String> query=nomi.Select(n=>n.ToUpper());
nomi.Add("Federica");
foreach(String n in query)
  Console.Write(n + "|");   Cristina|Federica|

Il nome Federica, pur essendo stato inserito dopo la creazione dell’oggetto query, e’ stato comunque preso in considerazione nel loop. Tutti gli operatori standard forniscono la deferred execution, tranne quelli che resituiscono uno scalare (First, Count) e gli operatori di conversione ToArray, ToList, ToDictionary, ToLookup, in quanto i tipi da loro restituiti non hanno meccanismi di deferred exec (ad es per Count il tipo int non puo’ essere enumerato).

La deferred exec e’ importante perche’ divide la costruzione della query dalla sua esecuzione, permettendo di costruire la query in piu’ passi, rendendo ad esempio possibili query linq to sql.

Come vengono eseguite le query?
IEnumerable<int>
source = new int[] { 5, 12, 3 },
filtered = source.Where(n => n < 10),
sorted = filtered.OrderBy(n => n),
q = sorted.Select(n => n *2);

foreach (int k in q)
Console.Write(k + “|”); // 6|10|

Si puo’ fare il paragone con una linea di produzione, che funziona solo on demand.
Costruire la query equivale a posizionare gli oggetti sulla linea mentre la linea non si muove, se non su richiesta dell’utilizzatore; a questo punto, partendo da dx verso sx, vengono attivati i rulli che fanno il loro lavoro (filtrare, ordinare, eccc)

Sviluppare con VB.NET e C# senza conoscere i fondamenti del framework e’ un po’ come guidare senza conoscere il motore dell’auto: si puo’ fare, ma se un giorno fosse necessario ridare l’esame della patente si verrebbe senz’altro bocciati….

In questa pagina voglio esplorare il framework partendo dalle sue fondamenta.

Ci sono impazzito per un po’, poi dopo un bel po’ di ricerche sono riuscito a far funzionare nusoap.php verso un webservice scritto in JAX.

Continuavo a ricevere Array ( [faultcode] => S:Client [faultstring] => Cannot find dispatch method for {}<metodo> ) e stavo per perdere le speranze, considerando che riuscivo a richiamare lo stesso servizio con un semplice client scritto in c# o vb.net.

Il segreto sta nello specificare il namespace che si trova nel wsdl, altrimenti si riceve sempre errore.

Codice di esempio minimale:

require_once(’nusoap.php’);
/* create client */
$endpoint = “http://<webservice address>?wsdl”;
$mynamespace = “http://WS/”; //vedi nel wsdl il targetNamespace
$client = new soapclient($endpoint);
$param = array(’par1′ => ‘val10);
$response = $client->call(’<method>’, $param, $mynamespace);
print($response);

Le lambda queries si basano sul concetto dei chaining operators, come nel seguente esempio:

string[] names={"Cris","Cristina","Federica"};
IEnumerable<string>query=names
     .Where(n=>n.Contains("a"))
     .OrderBy (n=>n.Length)
     .Select (n=>n.ToUpper());
foreach(string n in names)
      Console.WriteLine(n+ " | ");
     //CRISTINA | FEDERICA

Sarebbe equivalente scrivere:
var filtered = names.Where (n => n.Contains (”a”));
var sorted = filtered.OrderBy (n => n.Length);
var finalQuery = sorted.Select (n => n.ToUpper( ));

Le comprehension syntax queries forniscono una modalita piu’ veloce per scrivere query linq. Una cq comincia sempre con una clausola from e termina con un select o group. La from permette di dichiarare una variabile di iterazione che looppa attraverso la input collection.
Il compilatore trasforma una cq in una query lambda, cio’ implica che cio’ che puo’ essere scritta come comprehension query puo’ anche essere scritta come query lambda (ATTENZIONE !! ma non viceversa).

IEnumerable query =
     from   n in names
     where   n.Contains ("a")
     orderby n.Length
    select  n.ToUpper( );

viene trasformata in:

IEnumerable query = names
    .Where   (n => n.Contains ("a"))
    .OrderBy (n => n.Length)
    .Select  (n => n.ToUpper( ));

Sebbene superficialmente ricordino l’SQL, ci sono delle differenze: la query Linq si basa su espressioni C# e ne segue le regole, ad esempio non si puo’ usare una variabile prima di averla dichiarata, mentre in SQL si possono usare alias nella select che verranno definiti successivamente nella clausola from.
Una subquery linq e’ una espressione c# che non richiede sintassi speciale, le subquery sql talvolta richiedono regole particolari.

Con linq i dati passano sequenzialmente da sx a dx (o da su a giu a seconda di come lo si guarda), con l’sql l’ordine e’ piu’ casuale.
Una query linq e’ costituita da una pipeline di operatori che accettano e restituiscono sequence, l’sql comprendere una rete di clausole che lavorano su insiemi non ordinati.

Detto questo, la sintassi e’ simile.

A questo punto la domanda nasce spontanea? Lambda o comprehension query?

Ognuna ha i suoi vantaggi.

Le cq hanno una sintassi piu’ semplice nei seguenti casi:

  • clausola let per usare una nuova variabile durante una iterazione
  • utilizzo degli operatori SelectMany, Join, GroupJoin

Per gli operatori Where,OrderBy e Select l’uso e’ a discrezione dello sviluppatore.

Per tutti gli operatori che non sono Where, Select, SelectMany OrderBy, ThenBy, OrderByDescending, ThenByDescending Group, Join, GroupJoin si e’ obbligati a usare le lambda perche’ non esiste l’equivalente in CQ.

Mixed query

La perversione puo’ portare anche a utilizzarle entrambe, a patto che ogni componente cq sia completo, cioe’ inizio from from e termino con select o group.

Ad esempio:

int count = (from name in names
where n.Contains (”a”)
select name ).Count( );

Il Linq - Language Integrated Query - e’ stato inserito a partire dalla versione 3.5 del .Net Framework e consente di effettuare query strutturate su collezioni locali di oggetti che implementano l’interfaccia IEnumerable<>, tra cui arrays, XML Dom e su data sources remote (ad esempio tabelle Sql).

Le unita basilari di dati sono le sequence (oggetto che implementa IEnumerable) e gli elements (ogni singolo oggetto facente parte della sequence), come nel seguente esempio la sequence names comprende 3 elementi:

string[] names = { “Cris”, “Cristina”, “Federica” };

Una query Linq e’ un’espressione che trasforma una sequenza utilizzando utilizzando degli operatori:

IEnumerable<string> filteredNames =
System.Linq.Enumerable.Where(
names, n => n.Length > 4);

In questo caso l’operatore Where filtra in modo da estrarre solo gli elementi di lunghezza superiore a 4.

Dato che gli operatori sono implementati come metodi, si puo’ anche scrivere:

IEnumerable<string> filteredNames =
names.Where(n => n.Length > 4);

I due esempi precedenti utilizzano la lambda syntax, quello che segue la comprehension syntax:

IEnumerable<string> filteredNames=
from n in names
where n.Length>4
select n;

In tutti i suddetti casi, il risultato:

foreach (string n in filteredNames)
Console.Write(n + ” | “);

Produce: Cristina | Federica |

L’ho scoperto oggi e mi sembra fantastico: e’ un’applet java che prende in pasto un RSS e crea randomicamente una immagine a mo’ di tag clouds, l’effetto scenico e’ notevole

Dalla versione 3.5 di ASP.NET (VS 2008, per intendersi) il supporto per Ajax e’ built-in. Altrimenti lo si deve scaricare da qui.

Ecco un esempio minimale di applicazione ASP.NET che utilizza Ajax.

Dopo aver creato un web site, inserire dalla toolbox un controllo ScriptManager e un UpdatePanel, presi entrambi dal gruppo delle estensioni Ajax.

Il controllo ScriptManager puo’ andare all’inizio del body e occorre settare a True la proprieta EnablePartialRendering.

Il controllo UpdatePanel dovra’ contenere al suo interno, nel tag Content Template i server controls che si vogliono coinvolgere nella chiamata Ajax, il cui valore non verra’ sovrascritto nelle chiamate di postback.
Di seguito il codice della pagina .aspx:

<form id="form1" runat="server">
  <asp:ScriptManager ID="ScriptManager1" runat="server"
  EnablePartialRendering="true">
  </asp:ScriptManager>
  <div>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server"
    UpdateMode="Always">
      <ContentTemplate>
        <asp:Button ID="Button1" runat="server" Text="Button" />
        <br />
        <asp:Label ID="Label1" runat="server" Text="Label"/>
      </ContentTemplate>
    </asp:UpdatePanel>

  </div>
  </form>

Qui il code behind molto semplice:

Partial Public Class _Default
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, _
     ByVal e As System.EventArgs) Handles Me.Load
    label1.Text="Carico la pagina alle ore " & Now.ToString()
End Sub

Protected Sub Button1_Click(ByVal sender As Object, _
     ByVal e As EventArgs) Handles Button1.Click
    label1.Text = "Hai cliccato il bottone alle " & Now.ToString()
End Sub
End Class

I sorgenti posso essere scaricati qui

PDC 2008

Filed Under .Net | Leave a Comment

Sono online le registrazioni video delle sessioni del PDC 2008 appena svoltosi a Los Angeles. E’ un bel gesto da parte di MS nei confronti di coloro che non sono potuti esserci di persona. Grande :-)