In questo esempio è possibile vedere come caricare delle combo dinamicamente. Per far questo uso JQuery e le chiamate AJAX per recupperare i dati da una pagina ASP.NET che ritorna i dati necessari in formato JSON.

Ecco in pratica l'esempio:
Regione
Comune / Provincia

Per realizzare l'applicazione serve una pagina html con le combo e il codice javascript che, tramite JQuery, esegue le chiamate AJAX per recuperare i dati con cui riempire la combo Comune / Province.
<form action="" method="post" id="SgartComuni" onsubmit="return false;">
<table>
 <tr>
  <td>Regione </td>
  <td><select id="sgart_R" style="width:200px">
    <option value=""></option>
    <option value="ABR">Abruzzo</option>
    <option value="BAS">Basilicata</option>
    <option value="CAL">Calabria</option>
    <option value="CAM">Campania</option>
    <option value="EMR">Emiglia Romagna</option>
    <option value="FVG">Friuli Venezia Giuglia</option>
    <option value="LAZ">Lazio</option>
    <option value="LIG">Liguria</option>
    <option value="LOM">Lombardia</option>
    <option value="MAR">Marche</option>
    <option value="MOL">Molise</option>
    <option value="PIE">Piemonte</option>
    <option value="PUG">Puglia</option>
    <option value="SAR">Sardegna</option>
    <option value="SIC">Sicilia</option>
    <option value="TAA">Trentino Alto Adige</option>
    <option value="TOS">Toscana</option>
    <option value="UMB">Umbria</option>
    <option value="VDA">Valle D'Aosta</option>
    <option value="VEN">Veneto</option>
  </select>
  <span id="result"></span>
  </td>
 </tr>
 <tr>
  <td>Comune / Provincia</td>
  <td><select id="sgart_P" style="width:300px"></select></td>
 </tr>
</table>
</form>
<script language="javascript">
  $(document).ready(function(){
    $("#sgart_R").change(sgart_loadProvince);
  });

  //load combo province
  function sgart_loadProvince() {
    var codRegione = $("#sgart_R option:selected").val();

    $("#result").html("Attendi...");

    $.getJSON("/utility/comuni.aspx"
       , { q: codRegione, f: "codreg" }
       , function(data, textStatus) {
           var items = data;
           $("#sgart_P").html("");
           if (items.length == 0 ){
              $("#result").html("Attendi...");
           } else {
              var r = "";
              for (var i = 0; i < items.length; i++) {
                var code = items[i].CodProvincia;
                var description = items[i].Comune + " / " + items[i].Provincia;
                r += "<option value=\"" + code + "\">" + description + "</option>\r\n";
              }
              $("#sgart_P").html(r);
           }
           $("#result").html("");
         });
  }
</script>
Le cose interessanti che si possono vedere nell'esempio relative a JQuery sono:
  • come referenziare un oggetto nella pagina $("#idDelControllo")
  • come eseguire una funzione dopo che tutti gli elementi della pagina sono stati completamente caricati $(document).ready(..funzione..)
  • come aggiunge un evento ad un oggetto della pagina $("#idDelControllo").change(...nome della funzione...)
  • come recuperare l'elemento selezionato in una combo $("#idDelControllo option:selected").val(), notare option:selected
  • come aggiungere del codice html ad un controllo della pagina $("#idDelControllo").html(...codice html...)
  • ed in fine il metodo $.getJSON(...paginaAspx..., ...parametri..., ...funzione callback...) per eseguire chiamate asincrone (AJAX) a pagine sul server che ritornano dati in formato JSON

Per quanto riguarda la pagina che restituisce i dati, ho usato una normalissima pagina asp.net per farmi ritornare un array javascript in formato stringa (JSON).
I dati ritornati sono nel seguente formato:
[
{"Comune":"Abbadia Cerreto", "CodProvincia":"LO", "Provincia":"Lodi", "CodRegione":"LOM", "Regione":"Lombardia", "CAP":"20070", "PrefissoTelefonico":"0371", "CodErariale":"A003", "CodISTAT":"098001"},
{"Comune":"Abbadia Lariana", "CodProvincia":"LC", "Provincia":"Lecco", "CodRegione":"LOM", "Regione":"Lombardia", "CAP":"22050", "PrefissoTelefonico":"0341", "CodErariale":"A005", "CodISTAT":"097001"},
...
{"Comune":"Zone", "CodProvincia":"BS", "Provincia":"Brescia", "CodRegione":"LOM", "Regione":"Lombardia", "CAP":"25050", "PrefissoTelefonico":"030", "CodErariale":"M188", "CodISTAT":"017205"}
]
ovvero nel formato
[ 
{ "NomeCampo":valoreCampo , "NomeCampo":valoreCampo , ... }
,
{ "NomeCampo":valoreCampo , "NomeCampo":valoreCampo , ... }
,
...
{ "NomeCampo":valoreCampo , "NomeCampo":valoreCampo , ... }
]
Attenzione: il nomeCampo va racchiuso tra doppi apici.
Con jQuery JavaScript Library v1.3.2 funzionava anche senza, ma dalla versione 1.4.1 servono i doppi apici, come confermato da questo validatore json online.
La necessità di mettere i doppi apici sul valoreCampo dipende solo dal tipo di dato passato, se stringa ovviamente servono.
La pagina comune.aspx che ritorna i dati è la seguente:
File: comune.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Comuni.aspx.cs" Inherits="_Comuni" %>
File: comune.aspx.cs
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.OleDb;
using System.Configuration;
using System.Text;

public partial class _Comuni : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    Response.Clear();

    string connectionString = ConfigurationManager.ConnectionStrings["cnnAccess"].ConnectionString.Replace("~", Server.MapPath("/"));
    string referer = "";
    try
    {
      referer = Request.UrlReferrer.Host;
    }
    catch { }

    string search = "";
    string field = "";
    if (string.IsNullOrEmpty(Request["q"]) == false) search = Request["q"].Trim();
    if (string.IsNullOrEmpty(Request["f"]) == false) field = Request["f"].Trim().ToLower();

    string queryWhere = "";
    string queryKey = "";

    switch (field)
    {
      case "codprov":
      case "codprovincia":
        queryWhere = "C.[CodProvincia] = ?";
        queryKey = search;
        break;
      case "prov":
      case "provincia":
        queryWhere = "P.[Provincia] like ?";
        queryKey = string.Format("%{0}%", search);
        break;
      case "codreg":
      case "codregione":
        queryWhere = "P.[CodRegione] = ?";
        queryKey = search;
        break;
      case "reg":
      case "regione":
        queryWhere = "R.[Regione] like ?";
        queryKey = string.Format("%{0}%", search);
        break;
      case "cap":
        queryWhere = "C.[CAP] = ?";
        queryKey = search;
        break;
      case "tel":
      case "telefono":
        queryWhere = "C.[PrefissoTelefonico] = ?";
        queryKey = search;
        break;
      case "erariale":
        queryWhere = "C.[CodErariale] = ?";
        queryKey = search;
        break;
      case "istat":
        queryWhere = "C.[CodISTAT] = ?";
        queryKey = search;
        break;
      default:
        queryWhere = "C.[Comune] like ?";
        queryKey = string.Format("%{0}%", search);
        if (search.Length < 3) return;
        break;
    }

    StringBuilder sb = new StringBuilder(1000);
    sb.Append("[");

    if (!referer.Equals(Request.Url.Host, StringComparison.InvariantCultureIgnoreCase))
    {
      Add(sb
        , string.Format("Sono permesse connessioni solo dal dominio sgart.it ({0})", Request.Url.Host)
        , ".."
        , ".."
        , "..."
        , "..."
        , "....."
        , "...."
        , "...."
        , "......"
        );
    }
    else
    {
      string sql = string.Format(@" SELECT C.[ID], C.[Comune], C.[CodProvincia], P.[CodRegione], C.[CAP], 
       C.[PrefissoTelefonico], C.[CodErariale], C.[CodISTAT], P.[Provincia], R.[Regione]
        FROM TabRegioni R
          INNER JOIN (TabProvince P
            INNER JOIN TabComuni C ON P.CodProvincia = C.CodProvincia) ON R.CodRegione = P.CodRegione
         WHERE {0} 
       ORDER BY [Comune] ", queryWhere);

      using (OleDbConnection cnn = new OleDbConnection(connectionString))
      {
        using (OleDbCommand cmd = cnn.CreateCommand())
        {
          cmd.CommandText = sql;
          cmd.CommandType = CommandType.Text;
          cmd.Parameters.Add("q", OleDbType.VarChar, 50).Value = queryKey;
          cnn.Open();
          using (OleDbDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
          {
            bool comma = false;
            while (dr.Read() == true)
            {
              if (comma)
              {
                sb.Append(",");
              }
              comma = true;
              Add(sb
                , dr["Comune"].ToString()
                , dr["CodProvincia"].ToString()
                , dr["Provincia"].ToString()
                , dr["CodRegione"].ToString()
                , dr["Regione"].ToString()
                , dr["CAP"].ToString()
                , dr["PrefissoTelefonico"].ToString()
                , dr["CodErariale"].ToString()
                , dr["CodISTAT"].ToString()
                );
            }
          }
        }
      }
    }
    sb.Append("]");
    Response.Write(sb.ToString());
    Response.End();
  }

  protected void Add(StringBuilder sb, string comune, string codProvincia, string provincia
    , string codRegione, string regione
    , string cap, string prefissoTelefonico, string codErariale, string codISTAT)
  {
    sb.Append(@"{");
    sb.AppendFormat("\"Comune\":\"{0}\",", comune);
    sb.AppendFormat("\"CodProvincia\":\"{0}\",", codProvincia);
    sb.AppendFormat("\"Provincia\":\"{0}\",", provincia);
    sb.AppendFormat("\"CodRegione\":\"{0}\",", codRegione);
    sb.AppendFormat("\"Regione\":\"{0}\",", regione);
    sb.AppendFormat("\"CAP\":\"{0}\",", cap);
    sb.AppendFormat("\"PrefissoTelefonico\":\"{0}\",", prefissoTelefonico);
    sb.AppendFormat("\"CodErariale\":\"{0}\",", codErariale);
    sb.AppendFormat("\"CodISTAT\":\"{0}\"", codISTAT);
    sb.Append(@"}");
  }
}
in pratica in base hai parametri passati dalla chiamata AJAX, faccio una query su DB e costruisco la stringa che rappresenta l'array javascript.