Vlatkovic.NET

Web site o tehnologiji, programiranju, muzici, kuvanju, knjigama, u stvari o svemu i svačemu...
Dizajn: www.studio7designs.com opensource web templates.


Najnovije na blogu

 Tuesday, 15 January 2008
I opet malo programiranja, ovog puta o proširivanju postojećih asp.net severskih kontrola na primeru GridView-a.

Cilj ovog teksta je da pokaže kako se postojeće ASP.NET serverske kontrole mogu relativno lako dograditi tako da im se poveća funkcionalnost. Kao primer sam uzeo GridView koji u osnovnoj postavi nema  multiselect ali uz malo dorade postaje vrlo sličan gridovima koje srećemo u windows programiranju. Ideja je da možemo da izaberemo više redova u GridView tako što ćemo prilikom izbora držati taster CTRL.

Realizacija je sledeća: kad god kliknemo na neki red u GridView kontroli izvrši se registracija tog klika i nakon postback-a se čitaju indeksi kliknutih redova na osnovu kojih vraćamo redove u kontroli koji su izabrani.

Prvi korak je da kreiramo novu klasu koja će predstavljati DataGrid sa multiselect opcijom. Ona će biti izvedena iz  System.Web.UI.WebControls.GridView klase i čime obezbeđujemo nasleđivanje svih osobina i metoda ove klase na koje smo navikli.

public class MultiSelectGridView : System.Web.UI.WebControls.GridView

Zatim je potrebno da na svaki red koji generiše osnovna  GridView klasa “zalepimo” onclick javascript događaj (event handler). To radimo tako što promenimo OnRowDataBound metodu iz osnovne klase.

1: protected override void OnRowDataBound(GridViewRowEventArgs e)
2:  {
3:   base.OnRowDataBound(e);
4:
5:   if (e.Row.DataItem != null)
6:   {
7:    e.Row.Attributes.Add("OnClick", "msel(event)");
8:
9:    _id = this.PageIndex + "." + e.Row.RowIndex.ToString();
10:    e.Row.Attributes.Add("index", _id);
11:   }
12:  }

Glavna stvar se nalazi u liniji 7, gde na Row element dodajemo atribut OnClick koji će izvršavati msel(event) javascript funkciju na svaki klik. Javascript funkcija msel registruje gde se izvršio click događaj i upisuje indeks kliknutog elementa u skriveno (hidden) polje čiju vrednost ćemo kasnije, u postback-u, da parsiramo. Ovu funkciju ćemo da kreiramo i registrujemo kasnije.
Sledeća stvar se nalazi na linijama 9 i 10. Naime, tu kreiramo indeks elementa koji je kliknut i vezujemo ga za sam element. Njegova konstrukcija je vrlo jednostavna, “_id = broj stranice + tačka + indeks trenutnog reda”. Dobijeni indeks se upisuje kao dodatni atribut u element koji predstavlja red u GridView-u.
Da bi na klijentskoj strani znali koji red je izabran kreiramo Javascript funkciju “msel“ koju ćemo kasije da registrujemo na strani (podvučeni delovi code-a se automatski generišu u runtime-u).

Pre nego što prokomentarišem javascript code, da kažem par reči o html code-u koji generiše standardni GridView. GridView je u stvari obična tabela tj <table><tr><td>... konstrukcija. <tr> tag predstavlja red u našoj kontroli (Row) i na njega se “lepi” OnClick event. Sam event se zapravo okida na <td> elementu ali se propagira do prvog roditeljskog (parent) elementa koji ima handler tj definisan onclick a to je <tr> element. I evo javascript-a koji se generiše.
Da prokomentarišemo javascript.

1:<script language="javascript">
2: function msel(e, o)
3: {

kreiramo referencu na skriveni (hidden) html element koji u sebi sadrži informacije koji redovi su selektovani

4:  var selected = document.getElementById(o);

Zatim kreiramo referencu prema Event-u koji je inicirao izvršenje funkcije. Ova referenca nam treba da bi saznali koji je objekat inicirao Event i da li je pri kliku bio pritisnut taster CTRL. Linija 6 daje neposredni objekat koji je inicirao event, u ovom slučaju <td> tj ćeliju koja se nalazi unutar <tr> elementa. Na liniji 7 hvatamo sam <tr> element koji nosi informaciju o tome koji je indeks kliknutog elementa.

5:  e = e ? e : ((window.event) ? event : null);
6:  var obj = e.target ? e.target : ((e.srcElement) ? e.srcElement : null);
7:  obj = obj.parentElement ? obj.parentElement : obj.parentNode;
8:  var objParent = obj.parentElement ? obj.parentElement : obj.parentNode;

Na linijama 9 i 10  kreiramo objekte String tipa koji redom nose podatke o izabranim redovima i o trenutno kliknutom objektu tj njegovom indeksu.

9:  var sel = new String(selected.value);
10:  var id = new String(obj.getAttribute("index"));
11:  var cssclass;
12:  

Linija 13 ispituje da li je prilikom klika bio pritisnut i taster CTRL. Ukoliko jeste na liniji 14 proveravamo da li je red već izabran. Ukoliko jeste, ukloni ga iz liste izabranih i promeni css klasu za tekuću liniju. U suprotnom ubaci ga na listu izabranih i promeni css klasu.

13:  if (e.ctrlKey) {
14:   if (sel.indexOf("-" + id + "-") > -1) {
15:    selected.value = sel.replace("-" + id + "-", "");
16:    obj.className = "CssClassRow";
17:   }
18:   else {
19:    selected.value = sel + "-" + id + "-";
20:    obj.className = "CssClassRowSelected";
21:   }
22:  }

Ukoliko CTRL nije pritisnut (linija 23) lista izabranih indeksa svodi se na trenutno izabran a css klase se menjaju tako da su svi objekti neselektovani. 

23:  else {
24:   if (sel.indexOf("-" + id + "-") > -1) {
25:    cssclass = "CssClassRow"; selected.value = "";
26:   }
27:   else {
28v    cssclass = "CssClassRowSelected";
29:    selected.value = "-" + id + "-";
30:   }
31:   var trs = objParent.getElementsByTagName("tr");
32:   for(i = 0; i < trs.length; i++)
33:    if (trs[i].getAttribute("index"))
34:     trs[i].className = "CssClassRow";obj.className = cssclass;
35:    }
36:  }

 Napomena: podvučeni delovi se generišu

Funkcija  disableSelection samo ne dozvoljava da se na kliknutim redovima izvrši selekcija teksta. Za detalje pogledajte http://www.dynamicdrive.com/dynamicindex9/noselect.htm.

37: function disableSelection(target) {  
38:  if (typeof target.onselectstart!="undefined")   
39:   target.onselectstart=function(){return false;};  
40:  else if (typeof target.style.MozUserSelect!="undefined")    
41:   target.style.MozUserSelect="none";   
42:  else   
43:   target.onmousedown=function(){return false;};  
44:  target.style.cursor = "default";
45: }
46:</script>


Ok, sledeća metoda koju menjamo u odnosu na originalnu GridView klasu je OnRowCreated.

1:protected override void OnRowCreated(GridViewRowEventArgs e)
2:{
3: base.OnRowCreated(e);
4:
5: _id = this.PageIndex + "." + e.Row.RowIndex.ToString();
6:
7: if (selected != null && selected.IndexOf("-" + _id + "-") > -1)
8:     e.Row.CssClass = CssClassRowSelected;
9: else
10:     e.Row.CssClass = CssClassRow;
11:}

Opet kreiramo indeks, linija 5, i ako je trenutni red u listi selektovanih onda mu menjamo css klasu.

I na kraju menjamo CreateChildcontrols metodu. Zapravo samo je proširujemo. Cilj je da između svakog postback-a očuvamo stanje selektovanih redova.

1:protected override void CreateChildControls()
2:{

Naravno pustimo da se kreiraju sve potrebne kontrole koje se kreiraju za GridView (Linija 3)

3: base.CreateChildControls();
4:
5: string[] selectedArray;
6:
7: if (!string.IsNullOrEmpty(selected))
8: {

Izdvojimo indekse redova selektovanih na client strani (linija 9.) .

9:  selectedArray = selected.Split('-');
10:

Kreiramo listu int vrednosti koja će sadržati indekse izabranih redova.

11:  SelectedIndexs = new List<int>();

Kreiramo string niz koji će u sebi sadržati tekuću stranu i tekući index na strani.

12:  string[] pageAndIndex;

Za svaki element u selectedArray a na osnovu stranice i indeksa preračunamo pravi indeks i ubacimo u  SelectedIndexs.

13:  foreach (string s in selectedArray)
14:  {
15:   if (s.Length > 0)
16:   {
17:    pageAndIndex = s.Split('.');
18:    SelectedIndexs.Add(int.Parse(pageAndIndex[0]) * this.PageSize + int.Parse(pageAndIndex[1]));
19:   }
20:  }
21: }
22:

Registrujemo skriveno html polje u koje upisujemo koji su izabrani redovi.

23: this.Page.ClientScript.RegisterHiddenField(selectedKey, selected);

Registrujemo blok sa javascript funkcijama opisanim gore.

24: this.Page.ClientScript.RegisterClientScriptBlock( ( (System.Web.UI.WebControls.GridView)this).GetType(), "MultiselectGridView_js", js);
25:

I na kraju na GridView kontrolu dodamo još jednu literal kontrolu koja u sebi sadrži poziv funkcije  disableSelection koja ne dozvoljava da se selektuje tekst na upravo kreiranoj kontroli.

26: Literal l = new Literal();
27: l.Text = "<script language=\"javacript\" type=\"text/javascript\">disableSelection(document.getElementById(\"" + this.ClientID + "\"));</script>";
28: this.Controls.Add(l);
29:}

I to je to, kompletan code možete da skinete ovde.

Tuesday, 15 January 2008 23:41:27 (Central Europe Standard Time, UTC+01:00)