C# - Összetett web kontrol készítése

forráskód letöltése
Mostani példánkban egy olyan összetett web kontrolt készítünk, mely a következő funkciókat valósítja meg: tartalmát dinamikusan állítja elő annak függvényében, hogy egy DropDownList-ből milyen értéket választ a felhasználó. Választáskor automatikusan újabb kérés fut szerverünk felé, így az új tartalom generálása megtörténhet, csak kezelnünk kell ezt az eseményt. Kezeli továbbá a PostBack-et és ekkor olyan műveleteket hajt végre, mely szintén a kontrol kinézetét befolyásolja.
Mellékelt példa megnyitása előtt szükséges egy ListTest nevű virtuális könyvtár létrehozása, mely a példa könyvtárára mutat. Ehhez nyissa meg a mellékelt mappa Tulajdonság ablakát és itt a Webmegosztás lapon engedélyezze a mappa megosztását olvasási és parancsfájlok futtatási jogával.
Nézzük pontosan mit is kell tennie a kontrolunknak: elhelyezünk rajta egy DropDownList-et, melyből a felhasználó kiválaszthatja, hogy hány darab CheckBox kontrol jelenjen meg. A választott darabszámot egy Label-en is jelezzük. A választáskor automatikus postback történik, így a CheckBox-ok a megfelelő mennyiségben azonnal létrehozhatók.
Elhelyezünk még egy nyomógombot is, melyre kattintva megváltoztatható azon CheckBox-ok háttérszíne, melyet a felhasználó megjelölt (Checked == true).
A kontrolnak valós körülmények között semmi haszna, de a cél nem is ez, hanem annak bemutatása, hogy miként lehet egy kontrolon belül dinamikusan változtatni annak tartalmát, miközben többféle postback eseményt is kezel a kontrolunk.
A megvalósítás első lépése a gyermek kontrolok létrehozása, melyet a felülírt CreateChildControls függvényben tehetünk meg.
    protected override void CreateChildControls() 
    {
Készítünk egy Label-t a darabszám kijelzéséhez.
      l = new Label();
      l.Style.Add("left", "10");
      l.Style.Add("top", "10");
      l.Style.Add("position", "absolute");
      Controls.Add(l);
Létrehozunk egy DropDownList-et, melyben felsorolunk négy lehetséges darabszámot. Az AutoPostBack property-t igazra állítjuk, így rögtön új kérés indul alkalmazásunk felé, amint a felhasználó új értéket választ a listából. Ennek kezelésére létrehozunk egy eseménykezelőt a SelectedIndexChanged eseményhez.
      ddl = new DropDownList();
      ddl.Items.Add(new ListItem("Egy", "1"));
      ...
      ddl.AutoPostBack = true;
      ddl.Style.Add("left", "10");
      ddl.Style.Add("top", "40");
      ddl.Style.Add("position", "absolute");
      ddl.SelectedIndexChanged += new EventHandler(SelectedIndexChanged);
      Controls.Add(ddl);       
Létrehozunk négy CheckBox-ot is annak ellenére, hogy csak annyira lenne szükségünk ahányat a felhasználó kijelöl számunkra. Ennek ellenére a CreateChildControls függvényben érdemes minden esetben létrehozni az összes szükségessé válható kontrolt, majd a feleslegeseknél a Visible property hamisra állításával szabadulhatunk meg tőlük. Mivel ezen a ponton nem tudjuk, hogy mennyire lesz szükség, így mindegyiket hamisra állítjuk.
Ez a létrehozás már csak azért is szükséges, mivel egy PostBack esetén a CreateChildControls lehet, hogy le sem fut.
      string[] s = {"piros", "sárga", "kék", "zöld"};
      cb = new CheckBox[4];
      for (int i=0; i<4; i++)
      {
        cb[i] = new CheckBox();
        cb[i].Style.Add("top", (i*20+70).ToString());
        cb[i].Style.Add("left", "20");
        cb[i].Style.Add("position", "absolute");
        cb[i].Visible = false;
        cb[i].Text = s[i];
        Controls.Add(cb[i]);
      }     
Végül egy nyomógombot hozunk létre, melynek kezeljük a Click eseményét egy saját függvényen keresztül.
      Button b = new Button();
      b.Text = "Szín beállít";
      b.Style.Add("left", "180");
      b.Style.Add("top", "120");
      b.Style.Add("position", "absolute");
      b.Click += new EventHandler(ClickSendButton);
      Controls.Add(b);
    }
Tudjuk, hogy mielőtt a kontrol HTML kódja generálásra kerül még van olyan tevékenységünk, mely befolyásolja a kontrol kinézetét: CheckBox-ok láthatósága, választott darabszám megjelenítése. Erre jól alkalom az OnPreRender függvény futása. Itt a EnsureChildControls függvény hívásával biztosítjuk, hogy ha a CreateChildControls még nem futott le, akkor fusson. Ezt követően a gyerek kontrolok már biztos, hogy rendelkezésre állnak.
    protected override void OnPreRender(EventArgs e)
    {
      EnsureChildControls();      
Most már csak értéket adunk a darabszámot megjelenítő Label Text property-jének.
      l.Text = "Darabszám: " + ddl.SelectedItem.Value;
Beállítjuk, hogy hány CheckBox legyen látható és mennyi ne. Ehhez a count nevű változónk szolgáltatja az adatot, melynek értéke akkor változik, ha a felhasználó új értéket választ a DropDownList-ből.
      for (int i=0; i<count; i++)
      {
        cb[i].Visible = true;
      }     
Fontos, hogy a CheckBox-ok láthatósága tiltásra is kerüljön, mivel ha egyszer már lett engedélyezve, akkor egy postback esetén a láthatóság nem változik, vagyis kevés az, hogy a kontrolok létrehozásánál mindegyik CheckBox láthatóságát letiltjuk. Ez csak az első megjelenéskor játszik szerepet.
      for (int i=count; i<4; i++)
      {
        cb[i].Visible = false;
      }     
    }
Most már következhet a Render futása, ahol a megfelelő HTML kód generálása megtörténhet.
    protected override void Render(HtmlTextWriter writer)
    {                                                    
      EnsureChildControls();  
      Style.Add("position", "relative");
      base.Render(writer);
      Style.Add("width", Width.ToString());
      Style.Add("height", Height.ToString());
    }
Van még két eseményünk, melyeket kezelnünk kell. Elsőként nézzük azt, amikor a felhasználó darabszámot választ. Itt egyszerű a dolgunk: tároljuk a választott darabszámot a count nevű változónkba. Ez majd az OnPreRender függvény futásánál kerül felhasználásra.
    public void SelectedIndexChanged(object sender, EventArgs e)
    {
      count = Convert.ToInt32(ddl.SelectedItem.Value);
    }
A másik eset az, amikor a felhasználó a gombon kattint. Ekkor ismét szükségünk van az aktuálisan választott darabszámra, melyet egy ciklushoz használunk fel, ahol végignézzük, hogy mely CheckBox lett megjelölve és ezeknél megváltoztatjuk a háttérszínt.
    public void ClickSendButton(object sender, EventArgs e)
    {
      count = Convert.ToInt32(ddl.SelectedItem.Value);
      Color[] c = {Color.Red, Color.Yellow, Color.Blue, Color.Lime};
      for (int i=0; i<cb.Length; i++)
      {
        if (cb[i].Checked)
        {
          cb[i].BackColor = c[i];
        }
A ki nem jelölt CheckBox-oknál a háttérszínt visszaállítjuk fehérre.
        else
        {
          cb[i].BackColor = Color.White;
        }
      }
    }