TP

ASP.NET - Dynamické vytváření ovládacích prvků

Co tento článek ukazuje

Při tvorbě webových aplikací se můžete dostat do situace, kdy nevíte kolik ovládacích prvků budete potřebovat na stránce zobrazit (např. pokud chcete uživateli zobrazit CheckBoxy s možnostmi, které jsou uložené v databázi). V této situaci je potřeba vytvářet ovládací prvky dynamicky, tedy z kódu stránky.

Ukázková aplikace

Vytváření ovládacích prvků

Pokud chcete vytvářet ovládací prvky dynamicky je potřeba tyto prvky vytvořit dříve, než dojde k načtení stránky (pokud je budete vytvářet později, prvky se sice zobrazí, ale po provedení postbacku se ztratí v nich uložená data). Obvykle je nejlepší řešení vytvářet ovládací prvky v metodě OnInit. Vytvořené ovládací prvky si ASP.NET při post-backu automaticky nepamatuje a proto je potřeba vytvářet ovládací prvky ne jednou, ale při každém dotazu na stránku. Při vytváření ovládacích prvků je také potřeba vědět kam se prvky mají na stránku vkládat (je také důležité, aby se prvky vkládaly mezi form, který má nastavený atribut runat=server). K tomuto účelu je v ASP.NET ovládací prvek PlaceHolder, do kterého je možné pouze vkládat vytvářené ovládací prvky.

Kód, který vytvoří v metodě OnInit několik tlačítek a přidá je do PlaceHolderu placeCtrls vypadá takto:

// Vytvori 5 buttonu a prida je do placeCtrls
override protected void OnInit(EventArgs e)
{
  for(int i=1; i<=5; i++)
  {
    // Vytvori ovladaci prvek..
    Button btn=new Button();
    btn.ID=string.Format("btn{0}",i);
    btn.Text=string.Format("Cudlik {0}",i);
    // .. a prida ho do placeCtrls
    placeCtrls.Controls.Add(btn);
  }
  
  // Volani nutne pro Asp.Net
  InitializeComponent();
  base.OnInit(e);
}

Zpracování událostí

Pokud již vytváříte nějaké ovládací prvky, budete také pravděpodobně potřebovat k těmto ovládacím prvkům nějak přistupovat a nebo zachytávat jejich události. Nejprve se podíváme jak lze rozšířit předchozí ukázku tak, aby aplikace po stisknutí tlačítka vypsala jaké tlačítko bylo stisknuto. Nejprve je potřeba přidat kód, který přiřadí kliknutí na tlačítko nějakou událost. Pokud tuto událost přiřadíte všem generovaným tlačítkům, budete při její vyvolání potřebovat rozlišit, které tlačítko ji vyvolalo. Kvůli tomu předává ASP.NET jako první parametr události objekt který událost vyvolal (v našem případě stisknuté tlačítko).

// Prirazeni udalosti - 
// radku pridejte ke kodu generujicimu tlacitka
btn.Click+=new EventHandler(btn_Click);
...

// Metoda ktera zpracovava kliknuti
private void btn_Click(object sender, EventArgs e)
{
  // Zjisti objekt stisknuteho tlacitka
  Button clicked=(Button)sender;
  // Vypise text zobrazeny na tlacitku
  lblMessage.Text="Klikli jste na tlacitko: "+clicked.Text;
}
  

Přídávání ovládacích prvků

Kód ukázaný v předchozí ukázce ve většině případů plně postačuje. Občas je ale potřeba aby počet (typ a nebo nějaké jiné nastavení) ovládacích prvků mohl uživatel při práci se stránkou měnit. Tím se situace zkomplikuje hned ze dvou důvodů. Za prvé si stránka musí nějakým způsobem ukládat toto nastavení aby mohla při načítání vytvářet příslušné ovládací prvky a za druhé je potřeba aby aplikace nepřidávala ovládací prvky při zpracování nějaké události ale dříve (Například pokud uživatel klikne na tlačítko, které má přidat textové pole, je potřeba toto pole přidat ještě dříve než se událost ve skutečnosti vyvolá). Naznačení, jak řešit tyto problémy naleznete ve zbývající části článku, pro kompletní řešení se podívejte do zdrojových kódů.

Ukázková aplikace
Aplikace, která umožňuje přídávání textových polí

Přidávání textových polí

Nejprve se podíváme na druhý problém, tedy jak při kliknutí na tlačítko Přidat (btnAdd) vytvořit textové pole dříve než dojde k vyvolání události. Vzhledem k tomu, že ASP.NET generuje tlačítka jako input type="submit", lze k zachycení události využít vlastnosti HTML forumláře. Při kliknutí na submit tlačítko se předává v kolekci Request.Form jeho hodnota a tato kolekce je přístupná již v metodě OnInit. Pokud tedy máme na stránce tlačítko (btnAdd) a textové pole (txtName), je možné zjistit zda uživatel kliknul na tlačítko a jaký zadal text následujícím způsobem:

override protected void OnInit(EventArgs e)
{
  // Pokud uzivatel kliknul na tlacitko
  // bude zde vyplneno jmeno tlacitka
  if (Request.Form["btnGenerate"]!=null)
  {
    // Jmeno je nutne zjistit take pres Form,
    // protoze Asp.Net data jeste nenacetlo
    string jmeno=Request.Form["txtName"];
    ...
  }
  InitializeComponent();
  base.OnInit(e);
}

Ukládání nastavení ovládacích prvků

Druhým problémem, o kterém jsem se zmiňoval je potřeba ukládat nastavení o generovaných ovládacích prvcích. V ukázkové aplikaci (viz obrázek) je potřeba ukládat jména checkboxů, které se dynamicky vytvářejí. Když se podíváte, v jakém pořadí se zpracovávají ASP.NET stránky (viz [1]) je vidět, že toto nastavní se musí nastavit před načítáním dat ovládacích prvků (Process postback data). Pokud chceme toto nastavení ukládat do ViewState (což je nejrozumnější místo) tak ale nemůžeme ovládací prvky vytvářet již při OnInit, protože ViewState se načítá až později. Potřebujeme tedy nějakou metodu, která se volá pří, nebo po druhém kroku (Load view state). Tato metoda se (kupodivu) jmenuje LoadViewState, spolu s metodou SaveViewState je pomocí těchto dvou metod možné ovlivnit způsob jakým se ukládá ViewState stránky.

V ukázkové aplikaci bude tedy nastavení checkboxů ukládaáno v SaveViewState a toto nastavení budeme načítat ve volání LoadViewState (v tento okamžik je možné vytvářet ovládací prvky). Tyto metody obstarávají v ASP.NET stránce celé ukládání ViewState, takže při jejich úpravě je potřeba volat metodu předka, která zajišťuje zpracování ViewState všech ovládacích prvků na stránce.

Následující ukázka obsahuje pouze nejdůležitější část kódu, komletní příklad si můžete stáhnout
// Zde si pri nacteni ulozime nastaveni
string gen="";

// Uklada nastaveni do view state
// Metoda musi take ulozit nastaveni cele stranky
protected override object SaveViewState()
{
  object[] vs=new object[2];
  // Do pole se ulozi nastaveni ovladacich prvku
  vs[1]=gen;
  // .. a puvodni ViewState
  vs[0]=base.SaveViewState();
  return vs;
}

// Nacita nastaveni z view state
// Jako parametr Asp.Net predava cela data ve ViewState
protected override void LoadViewState(object savedState)
{
  object[] vs=(object[])savedState;
  string savedGen=(string)vs[1];
  ...
  VytvoritOvladaciPrvkyPodleNastaveni(savedGen);
  ...
  // Nacist puvodni ViewState pro zbytek stranky
  base.LoadViewState(vs[0]);
}

Soubory na stažení a odkazy

Published: Thursday, 5 May 2005, 11:24 PM
Author: Tomas Petricek
Typos: Send me a pull request!
Tags: