Potser m'avanço a coses que explicaré en la part client, però en una aplicació web, si es vol separar la presentació de les dades hi ha un punt de conflicte que són els combos (desplegables).
Les pàgines que genero només tenen HTML, sense dades, cal doncs un mecanisme per omplir els combos. De moment començaré per explicar la part servidora, un ASHX que es diu comboloader.
Aquest ASHX, s'encarrega de gestionar tots els combos de l'aplicació. Es recolza en la clsDades i derivades on normalment fa servir el mètode GET per anar obtenir els registres, muntar-los en JSON i enviar-los al navegador (al client). La part Javascript del comboloader s'encarrega de desmuntar aquest JSON i posar els valors corresponents als combos. Llavors quan es dissenya una pàgina un combo només és tag <select>, sense valors dins (a vegades es poden posar els valors si són coneguts i no hi ha gaires (ni previsió que hagin més)).
Del navegador es reben un conjunt de combos a carregar (els seus noms venen separats per "-"), els que apareixen en una pàgina i el que es fa es generar-los tots de cop. Per fer això necessitarem objectes que, un cop convertits a JSON donin suport a l'enviament de tots els combos amb els seus valors de cop. Són les classes: Combo i ComboItem.
Són dues classes molt senzilles. Comentar que potser hi ha combos en diferents parts de l'aplicació que tenen els mateixos items però diferents noms, aleshores el que es fa és afegir al "switch" que escull el combo a muntar més opcions. Això fa que moltes vegades ens trobem que el combo que volem muntar en realitat ja està fet per una altra pantalla. Llavors amb una simple línia de codi ja ho tenim enllestit. La construcció dels combos segueix la següent descripció:
Passos del programa
Com sempre el codi de cada fase, comencem per "obtenir els combos" i també al final "convertir a JSON i enviar":
/// <summary>/// Genera els items d'un combo/// </summary>/// <param name="TBL">Taula que conte els registres</param>/// <param name="CampID">Camp que va a la part de valor</param>/// <param name="CampDescripcio">Camp que serveix de descripció/// Pot estar format per més d'un camp</param>/// <param name="NumCombo">Número de l'array de combos</param>/// <param name="Separador">Si la descripció t'e més d'un camp, com es separen</param>/// <param name="ValorSiNull">Si hi ha alguna descripció nula</param>publicvoid GeneraItems(DataTable TBL, string CampID,
string CampDescripcio, int NumCombo, string Separador, string ValorSiNull)
{
DataRow DR;
string[] arrCampsDescripio = CampDescripcio.Split('-');
StringBuilder Descripcio = newStringBuilder();
string Camp = "";
if (TBL.Rows.Count > 0)
{
objCombos[NumCombo].Items = new ComboItem[TBL.Rows.Count];
for (int j = 0; j < TBL.Rows.Count; j++)
{
DR = TBL.Rows[j];
Descripcio.Length = 0;
objCombos[NumCombo].Items[j] = new ComboItem();
objCombos[NumCombo].Items[j].Val = DR[CampID].ToString();
for(int i = 0; i < arrCampsDescripio.Length; i++)
{
Camp = arrCampsDescripio[i];
if (i > 0) Descripcio.Append(Separador);
if (!DR.IsNull(Camp)) Descripcio.Append(DR[Camp].ToString().Trim());
else Descripcio.Append(ValorSiNull);
}
objCombos[NumCombo].Items[j].Disp = Descripcio.ToString().Trim();
}
}
}
#21/01/2014 22:54 Programació C# Autor: Alex Canalda
En tota aplicació web, la part servidora té números que hagi d'enviar dades en format JSON.
El mètode que he triat jo és fer servir una llibreria lliure que converteix objectes a JSON, i per la quantitat de projectes que porto amb aquesta llibreria funcionant bé, crec que ja és hora de recomanar-la. És la NewtonSoftJSON.
La particularitat que té i que m'agrada és que el valors NULL no els converteix a JSON, fent que sigui força optim enviar dades en JSON. Altres llibreries els valors NULLs es serialitzen com a: "nom_de_la_propietat":"", en aquesta és configurable. En el codi aquesta llibreria acostuma a aparèixer com un clsJSON.Serialize(objecte_dictionary) en els ASHX.
Al ser una llibreria no posaré el codi per que seria només la línia que he comentat abans, però si cal recordar que s'ha de posar una referència a la DLL corresponent.
Referència afegida
#20/01/2014 11:24 Programació C# Autor: Alex Canalda
Dins de la construcció d'un grid, en la part que toca a un ASHX, el que cal saber és la seva configuració i com funcionen la clsColumna i clsCampBBDD. No cal conèixer en detall aquesta funció de la clsHelper, però si ens agrada el codi com a mi, no està de més saber com funciona per dins.
Tots el grids d'una aplicació fan servir aquesta funció, porto uns quants projectes a l'esquena fent-la servir, així que penso que està amortitzada i no he trobat bugs aparents, però si en trobo almenys al corregir-ho serveix per tots.
El primer que fa aquesta funció és recuperar els valors dels paràmetres que indiquen la pàgina, l'ordre, etc... aquest paràmetres els genera el grid automàticament a la part client, en la part servidora només els recuperem.
sidx: camps pel que es fa l'ordenació.
sord: sentit de la ordenació, ascendent o descendent.
rows: número de files a recuperar.
page: pàgina a recuperar.
A més a més d'aquests paràmetres a la URL també es posen els camps i els corresponents valors que es fan servir per filtrar el resultats. Es recuperen també, venen donats a la StringCollection CampsClau.
Durant el procés de recuperar aquests valors també es munta una clau que identifica de forma única un grid, i l'estat en que es troba. Com estat en que es troba s'enten: la pàgina, ordre, número de registres, filtre aplicat etc... Aquesta clau es fa servir per consultar la cache. A la cache de grids s'accedeix mitjaçant aquesta clau, un identificador de grid i la taula sobre la que s'aplica. Les operacions d'INS, UPD i DEL, en cas de tenir cache que la taula es gestioni amb cache, esborren els registres de la taula de cache només d'aquesta taula en concret. Un muntada aquesta clau es mira la taula de cache, si es troba es recupera el JSON i s'envia directament. D'això s'anomena un "cache hit". Si no es troba (un "cache miss") es segueix processant normalment i es crida a la funció QUERY (aquesta al seu temps cridarà a la SP QUERY). La diferència entre operar amb cache o sense és molt gran quan es fan QUERYs contra taules de milions de registres ja que els usuaris acostumen a treballar habitualment amb el mateix subconjunt de dades, es a dir no tots els registres tenen la mateixa importància.
Un cop obtinguts els registres cal empaquetar els camps en els objectes clsGridRow corresponents, donant format a les dades en cas de que estigui informat el camp "Format".
Un cop fet això poc queda per fer. Convertir-ho a JSON. Si la taula es gestiona amb cache, aquest JSON cal guardar-lo, d'aquesta manera el proper cop hi haurà un "cache hit" (de fet només que l'usuari refresqui la pàgina ja farà un hit).
Com sempre el codi:
/// <summary>/// Genera els camps d'un grid/// </summary>/// <param name="TA">TableAdapter del tipus de registres que té que generar</param>/// <param name="Req">Request del que treure informació</param>/// <param name="CampsClau">Si el grid es filtra per algun camp informar-los aqui,/// primer es busquen en el Request, després en ValorsExtraCampsClau</param>/// <param name="ValorsExtraCampsClau">OPCIONAL: Valors de camps Clau que no arriben/// a través del Request, passar null si no es vol</param>/// <param name="ColumnesGrid">Llista de columnes del Grid, ha d'estar
/// en l'ordre que estan a pantalla d'esquerra a dreta</param>/// <param name="GridID">ID del Grid que es genera, només es fa servir quan hi ha cache</param>/// <returns></returns>publicstaticstring LoadGrid(clsDades TA, HttpRequest Req, StringCollection CampsClau,
List<clsColumna> ColumnesGrid, Dictionary<string, string> ValorsExtraCampsClau, string GridID)
{
bool Search = false;
int i = 0;
string Ordenacio = "";
string SentitOrdre = "";
int numRegistres = 0; //Numero de registres per cada paginaint numPag = 0; //Pagina que es volint numTotalRegs = 0;
int numTotalPags = 1; //Numero total de paginesDataTable TBL;
DataRow DR;
Dictionary<string, string> Params = newDictionary<string, string>();
Dictionary<string, string> ParamsCache = newDictionary<string, string>();
clsGridRow GR;
string Valor = "";
decimal ValorDecimal = 0;
DateTime ValorDateTime;
clsCache Cache = new clsCache(TA.CadConnBBDD);
string Result = "";
StringBuilder URL = newStringBuilder();
if (Req["_search"] != null)
bool.TryParse(Req["_search"], out Search);
Ordenacio = Req["sidx"];
SentitOrdre = Req["sord"].ToUpper();
clsGridResponse Data = new clsGridResponse();
numRegistres = int.Parse(Req["rows"]);
numPag = int.Parse(Req["page"]);
foreach (string Clau in CampsClau)
{
if (!string.IsNullOrEmpty(Req[Clau]))
{
Params.Add(Clau, Req[Clau]);
URL.AppendFormat("-{0}-{1}", Clau, Req[Clau]);
}
else
{
if (ValorsExtraCampsClau != null)
{
if (ValorsExtraCampsClau.ContainsKey(Clau))
{
Params.Add(Clau, ValorsExtraCampsClau[Clau]);
URL.AppendFormat("-{0}-{1}", Clau, ValorsExtraCampsClau[Clau]);
}
}
}
}
if (TA.TeCache)
{
URL.AppendFormat("{0}{1}", Ordenacio.ToString(), SentitOrdre.ToString());
URL.AppendFormat("{0}{1}", Req["rows"], Req["page"]);
ParamsCache.Add("Taula", TA.NomTaula);
ParamsCache.Add("URL", URL.ToString());
ParamsCache.Add("GridID", GridID);
TBL = Cache.GET(ParamsCache);
if (TBL.Rows.Count != 0)
{
//Cache hit
Result = TBL.Rows[0]["JSON"].ToString();
return Result;
}
}
//Processat sense cache
Params.Add("PageSize", numRegistres.ToString());
Params.Add("PageNum", numPag.ToString());
Params.Add("SortColumn", Ordenacio + SentitOrdre);
TBL = TA.QUERY(Params, out numTotalRegs);
#if DEBUG
foreach (clsColumna ColumnaGrid in ColumnesGrid)
{
foreach (clsCampBBDD CampGridBBDD in ColumnaGrid.Camps)
{
if (!TBL.Columns.Contains(CampGridBBDD.Nom))
{
thrownewException("ERROR: La columna " + CampGridBBDD.Nom + " no pertany a la taula del LoadGrid");
}
}
}
#endif
numTotalPags = numTotalRegs / numRegistres;
if (numTotalRegs % numRegistres != 0) numTotalPags++;
Data.total = numTotalPags.ToString();
Data.page = Req["page"];
//Generacio de les dades en JSONfor (i = 0; i < TBL.Rows.Count; i++)
{
GR = new clsGridRow();
DR = TBL.Rows[i];
foreach (clsColumna ColumnaGrid in ColumnesGrid)
{
Valor = "";
for (int j = 0; j < ColumnaGrid.Camps.Count; j++)
{
if (j != 0) Valor += ColumnaGrid.Separador;
if (!DR.IsNull(ColumnaGrid.Camps[j].Nom))
{
if (ColumnaGrid.Camps[j].Format != "")
{
switch (ColumnaGrid.Camps[j].Tipus)
{
case"System.DateTime":
ValorDateTime = (DateTime)DR[ColumnaGrid.Camps[j].Nom];
Valor += ValorDateTime.ToString(ColumnaGrid.Camps[j].Format);
break;
case"System.Decimal":
ValorDecimal = (Decimal)DR[ColumnaGrid.Camps[j].Nom];
Valor += ValorDecimal.ToString(ColumnaGrid.Camps[j].Format);
break;
}
}
else Valor += DR[ColumnaGrid.Camps[j].Nom].ToString();
}
else Valor += ColumnaGrid.Camps[j].ValorSiNull;
}
GR.cell.Add(Valor);
}
Data.rows.Add(GR);
}
Data.records = numTotalRegs.ToString();
Result = clsJSON.Serialize(Data);
//Es un MISS cal fer un insert a la cacheif (TA.TeCache)
{
Params.Clear();
Params.Add("Taula", TA.NomTaula);
Params.Add("URL", URL.ToString());
Params.Add("GridID", GridID);
Params.Add("JSON", Result);
Cache.INS(Params);
}
return Result;
}
#17/01/2014 13:47 Programació C# Autor: Alex Canalda
Quan en una aplicació web, en un ASHX, es fa un grid hi ha que fer una crida a la clsHelper LoadGrid amb uns paràmetres en concret. Aquests paràmetres es creen fent servir les classes clsColumna i clsCampBBDD que estàn explicades aquí.
Cal tenir en compte que alhora de definir les columnes aquestes han d'estar en el mateix ordre que al grid. En el codi a continuació es poden veure exemples de columnes compostes per més d'un camp de BBDD, formatades, que passa si el valor és null, etc... Millor veiem l'exemple:
privatevoid LoadGrid()
{
string JSON;
StringCollection CampsClau = newStringCollection();
List<clsColumna> ColumnesGrid = newList<clsColumna>();
clsColumna ColumnaGrid;
string PK_Arxiu = "";
Dictionary<string, string> ValorsExtra = newDictionary<string, string>();
clsCampBBDD CampGridBBDD;
clsDestruccio TA = new clsDestruccio(ConnStr);
//Això és concret d'aquesta aplicació//Però serveix per ilustrar els ValorsExtra//En aquest cas es vol limitar els resultats del grid//segons un valor que no arriba en la petició, està//associat a l'usuari
PK_Arxiu = clsHelper.ObtenirArxiu(IdPersona, ConnStr, null, null);
//Aquests camps arriben per la URL i serveixen//per filtrar el grid.
CampsClau.Add("PK_Destruccio");
CampsClau.Add("FK_TAAD");
CampsClau.Add("Exped_I");
CampsClau.Add("DataInici");
CampsClau.Add("DataFi");
CampsClau.Add("FK_Estat");
CampsClau.Add("FK_Arxiu");
//S'afegeix el valor que també filtra però no//arriba a la URL
ValorsExtra.Add("FK_Arxiu", PK_Arxiu);
// columna 1
ColumnaGrid = new clsColumna();
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "PK_Destruccio";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
// columna 2
ColumnaGrid = new clsColumna();
//Aquesta columna està formada per 2 camps, separats per -
ColumnaGrid.Separador = " - ";
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "codi_TAAD";
ColumnaGrid.Camps.Add(CampGridBBDD);
//Segon camp de la columna 2
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "Descripcio";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
// columna 3
ColumnaGrid = new clsColumna();
//Aquesta columna està formada per 2 camps, separats per /
ColumnaGrid.Separador = "/";
CampGridBBDD = new clsCampBBDD();
//Si és null es posarà un - enlloc del valor
CampGridBBDD.ValorSiNull = "-";
CampGridBBDD.Nom = "Codi_TC";
ColumnaGrid.Camps.Add(CampGridBBDD);
//Segon camp de la columna 3
CampGridBBDD = new clsCampBBDD();
//Si és null es posarà un - enlloc del valor
CampGridBBDD.ValorSiNull = "-";
CampGridBBDD.Nom = "Especifica_TC";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
// columna 4
ColumnaGrid = new clsColumna();
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "Serie_documental";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
// columna 5
ColumnaGrid = new clsColumna();
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "Any_obertura";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
// columna 6
ColumnaGrid = new clsColumna();
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "Any_tancament";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
// columna 7
ColumnaGrid = new clsColumna();
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "Metres";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
// columna 8
ColumnaGrid = new clsColumna();
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "NumExpedients";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
// columna 9
ColumnaGrid = new clsColumna();
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "Estat";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
// columna 10, datetime sense hora
ColumnaGrid = new clsColumna();
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "Data_Destruccio";
CampGridBBDD.Tipus = "System.DateTime";
//Aquí es fa servir el format, es pot especificar un//format diferent al que es fa servir en el detall//d'un formulari
CampGridBBDD.Format = "dd/MM/yyyy";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
// columna 11
ColumnaGrid = new clsColumna();
CampGridBBDD = new clsCampBBDD();
CampGridBBDD.Nom = "bCataleg";
ColumnaGrid.Camps.Add(CampGridBBDD);
ColumnesGrid.Add(ColumnaGrid);
JSON = clsHelper.LoadGrid(TA, Req, CampsClau, ColumnesGrid, ValorsExtra, "");
Resp.Write(JSON);
}
#17/01/2014 13:06 Programació C# Autor: Alex Canalda
Els grids són la part més difícil d'una aplicació web. Jo faig servir el papa de tots els grids: el Trirand jqGrid. De fet ja fa força anys que el faig servir (uis! hem faig vell!).
Com aquí em tinc que limitar a tractar la part servidora que està en un ASHX, direm que l'objectiu és: donada una petició cal muntar el JSON corresponent per alimentar al grid.
Muntar aquest JSON té certa gràcia ja que ha de tenir una estructura concreta, per això cal fer unes classes que quan es converteixen a JSON encaixin amb el que necessita el grid. A més a més d'això cal cridar a mètode QUERY de la classe derivada de la clsDades corresponent. Per ja fer triple carambola, hi ha columnes d'un grid que estan compostes de varis camps de la BBDD ajuntats. Començarem doncs per les classes que s'han d'omplir per generar el JSON, són la clsGridResponse i la clsGridRow:
Per descarregar una mica la complexitat de definir un grid amb columnes compostes de varis camps de la BBDD, vaig fer uns altres objectes on informar aquesta configuració, són les clsColumna i la clsCampBBDD.
/// <summary>/// Classe que defineix una columna d'un grid./// També es fa servir durant l'exportació a Excel/// </summary>publicclass clsColumna
{
/// <summary>/// Camps que composen la columna/// </summary>publicList<clsCampBBDD> Camps {get; set;}
/// <summary>/// En el cas d'una columna amb més d'un camp a BBDD/// és el caràcter que les separa, p. ex: '/' o '-'/// </summary>publicstring Separador {get; set;}
/// <summary>/// En el cas de l'exportació a Excel és el nom de la columna,/// quan es fa servir un grid no cal informar-lo perque ja/// està el nom al JS on es defineix el grid./// </summary>publicstring Nom {get; set;}
public clsColumna()
{
Camps = newList<clsCampBBDD>();
Separador = "";
Nom = "";
}
}
/// <summary>/// Camps de la BBDD del que està formada una columna/// </summary>publicclass clsCampBBDD
{
/// <summary>/// Nom del camp de BBDD/// </summary>publicstring Nom { get; set; }
/// <summary>/// En el cas que sigui null el valor es posar aquest valor, p. ex: '-'/// </summary>publicstring ValorSiNull { get; set; }
/// <summary>/// En el cas de ser DateTime o Decimal/// es pot especificar el format, p. ex: 'dd/MM/yyyy' o '#.00'/// </summary>publicstring Format { get; set; }
/// <summary>/// Admet 3 valors: res ("") , 'System.DateTime' o 'System.Decimal'/// </summary>publicstringTipus { get; set; }
public clsCampBBDD()
{
Nom = "";
ValorSiNull = "";
Format = "";
Tipus = "";
}
}
I aquestes classes de suport on es poden posar? Doncs tota aplicació té un calaix de mals endreços on van a parar aquest tipus d'objectes. En el meu cas es diu clsHelper, i mereix un post apart. Aleshores, per fer un grid, el que cal fer es configurar aquestes classes i cridar al Loadgrid genèric de la clsHelper, un exemple d'aquesta configuració.
#16/01/2014 17:43 Programació C# Autor: Alex Canalda
Aquesta acostuma a ser una operació senzilla dins d'una aplicació, sigui web o no. Només cal invocar al ASHX amb l'acció corresponent, la clau primària i llestos. De fet és una crida Ajax força curta, i la poso en un botó al formulari web. També es pot invocar des d'un grid fent un botó adhoc. Un cop rebuda la petició no cal fer res més que crida al DEL de la classe derivada de la clsDades. Alguna vegada m'he trobat que cal fer verificacions de que el registre no tingui altres vinculats en altres taules per donar el missatge pertinent, però res més complicat que això. En l'exemple que hi ha a continuació s'esborra el fitxer que hi ha associat i després el registre de la BBDD.
Seguint la sèrie de posts dedicats al desenvolupament d'aplicacions web, ara toca processar una petició de nou registre que arriba des del formulari web. Aquesta part del ASHX òbviament crida a la deserialització per obtenir els valors dels camps que arriben al "request" que es col·loquen en un Dictionary (és un objecte que té una estructura clau-valor, que faig servir per posar nom_camp_BBDD-valor_camp) i posteriorment es crida a l'INS de la classe derivada corresponent (derivada de la clsDades). Aquest mecanisme de deserialització fa que no importi el nombre de camps que hi ha al formulari, 5 o 50 ens costarà el mateix de programar. La llista de camps a deserialitzar la genera un programa a partir dels camps a la BBDD i amb un "checkbox" (casella de verificació? Que malament sona), deia que amb un "checkbox" es decideix si es deserialitza o no. De forma similar al Update també es pot posar aquí verificacions de negoci, o es pot afegir al Dictionary algo com la data de creació del registre... La diferència principal respecte l'update és que es recull el valor del clau primària (PK, primary key) que es genera i s'envia al formulari web. Un cop el formulari web rep aquest PK, el formulari passa de mode insert a mode update, ja que posteriors gravacions no crearan registres nous si no que actualitzaran el mateix registre tota l'estona. La plantilla que genera ASHXs crea aquest mètode "Insertar", com sempre el codi comentat:
privatevoid Insertar()
{
Resp.ContentType = "plain/text";
Req.ContentEncoding = Encoding.GetEncoding("UTF-8");
try
{
//Clase derivada de clsDades que té informació sobre el camps a//Deserialitzar
clsClassificacio ClassificacioTA = new clsClassificacio(ConnStr);
//Objecte Dictionary on guardarem nom_camp-valor_campDictionary<string, string> Params = newDictionary<string, string>(); ;
//Verificació de la lògica de negocistring Errors = ComprovacionsDadesUpdateInsert();
if (Errors == "")
{
decimal PK_Classificacio;
//Deserialitzar propiament dit
Params = ClassificacioTA.Deserialize(Req);
//Obtenim la nova PK
PK_Classificacio = ClassificacioTA.INS(Params);
//S'envia la PK al formulari
Resp.Write(PK_Classificacio.ToString());
}
else
{
Resp.Write(Errors);
}
}
catch (Exception Err)
{
Resp.Write("ERROR: " + Err.Message);
}
}
#15/01/2014 10:26 Programació C# Autor: Alex Canalda
No sóc dissenyador, però a vegades faig veure que ho sóc amb més o menys encert. I ja se que es poden fer servir fonts als CSS desde fa "temps" (en termes informàtics el temps és relatiu).
L'altra dia em vaig animar a posar fonts diferents al blog. I he vist que no és sencill. El primer pas és aconseguir les fonts, m'agrada fer-me les coses jo mateix però a les fonts encara no arriba el meu masoquisme. Per això les he agafat de Google.
He fet servir la lobster pel títol del blog i la nunito pel títol dels posts.
Les fonts
La forma de posar al CSS també és curiosa. Quan descarregues les fonts tens un munt de fitxers amb la font "regular" (normal), "bold" (negreta), "italic", "thin"... Els navegadors si poses la regular però després dius que la vols negreta fan un "faux" bold (o una negreta falsa). I el mateix per la itàlica, tens la regular i li dius que la vols itàlica i et fa una itàlica falsa. El que cal fer és incloure el fitxer "bold" i el fitxer de la "italic". Però enlloc de fer una font NunitoRegular, una altra NunitoBold i una NunitoItalic en el CSS s'ha de fer amb el mateix nom però modificant les propietats "font-weight" (normal o bold) i "font-style" (normal o italic). Aquí trobareu un article que ho explica millor que jo. Jo no ho he tingut que fer per que només faig servir la "regular" de la font Nunito i la font "lobster" només té regular, però poso el codi com sempre:
Els ASHX han de permetre actualitzar dades i aquesta funció s'encarrega d'actualitzar el registre que està mostrant actualment un formulari. Es poden donar molts casos, per exemple que el formulari mostri dades de més d'una sola taula. No passa res, quan es cridi a les funcions de deserialització corresponents cadascuna agafarà els camps que li pertoca. La única condició es que els camps del formulari tinguin noms diferents. Igual que al serialitzar no importa que el formulari tingui 5 camps o 50, el cost de programació (en aquest punt) és el mateix. La informació sobre els camps a recuperar estarà en una classe derivada de la clsDades. També acostuma a passar que els camps que es mostren en un formulari no són tots els que es mostren al formulari, llavors el que es fa és carregar el registre amb un GET prèviament i després deserialitzar només els camps que s'actualitzen fent un UPD. L'exemple que es mostra a continuació és aquest cas. També en aquesta funció es sol afegir lògica de verificació que sigui de negoci (la típica de camps buits, números i dates es posa al navegador).
privatevoid UpdateData()
{
Resp.ContentType = "plain/text";
Req.ContentEncoding = Encoding.GetEncoding("UTF-8");
try
{
//Classe derivada de clsDades
clsClassificacio ClassificacioTA = new clsClassificacio(ConnStr);
DataTable TBL;
DataRow DR;
//Dictionary per recuperar dadesDictionary<string, string> Params = newDictionary<string, string>();
string pPK_Classificacio = Req["PK_Classificacio"];
//Es verifica la lógica de negocistring Errors = ComprovacionsDadesUpdateInsert();
if (Errors != "")
{
Resp.Write(Errors);
}
else
{
//Es recuperen les dades
Params.Add("PK_Classificacio", pPK_Classificacio);
TBL = ClassificacioTA.GET(Params);
DR = TBL.Rows[0];
//Es deserialitza
ClassificacioTA.Deserialize(DR, Req);
//Es fa el Update
ClassificacioTA.UPD(DR);
Resp.Write("Update Classificacio OK");
}
}
catch (Exception Err)
{
Resp.Write("ERROR: " + Err.Message);
}
}
#13/01/2014 16:08 Programació C# Autor: Alex Canalda
Una de les accions del ASHX és obtenir un registre de la BBDD (fent servir les "stored procedures" i la clsDades), serialitzar els camps que formen el registre, convertir-ho a JSON i enviar-ho al navegador. El millor d'aquest proces és que el seu cost no depèn del número de camps que té el formulari al que van destinades les dades. És a dir em resulta igual que el formulari tingui 5 camps o 50. La funció que s'encarrega de fer això és diu LoadData, normalment recupera la clau primària sobre la que ha de retornar un registre. El generador que fa ASHX a partir d'una plantilla genera aquesta funció automàticament. Com sempre el codi:
privatevoid LoadData()
{
//Es posa el content type que toca
Resp.ContentType = "application/json";
//Paràmetres per fer la cridaDictionary<string, string> Params = newDictionary<string, string>();
//Clase derivada de la clsDades que té la informació//dels camps a serialitzar
clsDestruccio TA = new clsDestruccio(ConnStr);
//Recollim la PKstring pPK_Destruccio = Req["PK_Destruccio"];
Params.Add("PK_Destruccio", pPK_Destruccio);
//Fem un GETDataTable TBL = TA.GET(Params);
//Es serialitza i s'envia el JSON//al fer la serialització no importa que siguin 5 camps o 50
Resp.Write(TA.Serialize(TBL.Rows[0]));
}
#13/01/2014 12:51 Programació C# Autor: Alex Canalda