Első lépésként egy szokásos kapcsolatot építünk ki az MS SQL Northwind adatbázisával. Mellékelt példa használatához adja meg a szerver nevét, valamint a bejelentkező nevet és jelszót.
private void button1_Click(object sender, System.EventArgs e)
{
connection = new SqlConnection("Data Source="+textBox1.Text+";uid="+textBox2.Text+";password="+textBox3.Text+";initial catalog=Northwind;Connect Timeout=3");
connection.Open();
Amint az adatbázis kapcsolat adott, futtatunk egy igen egyszerű lekérdezést a Products táblára, melynek eredményét egy DataSet-ben tároljuk.
da = new SqlDataAdapter("select * from Products", connection);
da.Fill(ds, "Products");
A tábla egyes oszlopait hozzákötjük egy-egy TextBox-hoz, illetve a termékek azonosítóját egy Label-hez, hogy az ne váljon szerkeszthetővé.
label1.DataBindings.Add("Text", ds, "Products.ProductID");
textBox4.DataBindings.Add("Text", ds, "Products.ProductName");
textBox5.DataBindings.Add("Text", ds, "Products.QuantityPerUnit");
Amikor változik az aktuális rekord pozíció a táblában, akkor erről kérhetünk egy eseményt a BindingContext-től. Ehhez csak annyi a teendőnk, hogy a PositionChanged eseményhez hozzárendeljünk egy eseménykezelő eljárást, mely meghívásra kerül minden olyan esetben, amikor a rekord pozíció változik.
this.BindingContext[ds, "Products"].PositionChanged += new System.EventHandler(DoPositionChanged);
Ez az eseménykezelő függvény a DoPositionChanged belső függvényünk lesz. Ennek feladata, hogy kiírja az aktuális rekord sorszámát a StatusBar-ra. Ezt a függvényt most rögtön meg is hívjuk, hogy aktualizáljuk a kiírást.
DoPositionChanged(null, null);
...
}
Nézzük, hogy is történik ez a kiírás. A BindingContext adott elemének Position property-jéből olvashatjuk ki az aktuális rekord sorszámát. Ez a sorszám nullától indul, tehát az első rekord a nulladik sorszámú.
private void DoPositionChanged(object sender, System.EventArgs e)
{
statusBarPanel1.Text = "Row: " + (this.BindingContext[ds, "Products"].Position + 1);
}
Tegyünk egy kis kitérőt és nézzük is meg, hogy mit takar a BindingContext[ds, "Products"] kifejezés. Bár ránézésre érthető, hogy e kifejezés az adott DataSet-en belüli Products táblát adja, nézzük, hogy milyen típusú objektumokról is van szó.
A BindingContext osztálynak van egy Item nevű property-je, melynek két változata is létezik. Ez a property egy tömb, melynek minden eleme ListManager osztályt tartalmaz. A property egyik változata esetén csak a DataSet-et kell megadni, másik esetben még egy sztringet is, melyben a tábla nevét adhatjuk meg. Így a BindingContext[ds, "Products"] használata esetén valójában a BindingContext.Item[ds, "Products"] kifejezést használjuk.
Nézzük most, hogy a ListManager osztály milyen tulajdonságokkal rendelkezik.
A Position property-vel már találkoztunk, ez adja meg az aktuális rekord pozíciót, sőt ezzel állíthatjuk is azt.
private void button3_Click(object sender, System.EventArgs e)
{
if (this.BindingContext[ds, "Products"].Position>0)
{
this.BindingContext[ds, "Products"].Position--;
}
}
A másik lényeges kérdés, hogy hány eleme, rekordja is van az adott táblának. Ehhez a Count property használatára lesz szükségünk, mely ezt a számot tárolja.
private void button4_Click(object sender, System.EventArgs e)
{
if (this.BindingContext[ds, "Products"].Position<this.BindingContext[ds, "Products"].Count-1)
{
this.BindingContext[ds, "Products"].Position++;
}
}
A Current property az aktuális elemet adja vissza object típusban. Például, ha az adatforrás DataView vagy DataTable típusú, akkor erre a property-re nyugodtan rádefiniálhatjuk a DataRowView osztályt, mivel ez esetben ilyen típusban kerül visszaadásra a Current.
A DataSource property-ben érhető el a ListManager által kezelt adatforrás, mely a következők közül kerülhet ki:
- DataTable
- DataView
- DataSet
- DataSetView
- Egy dimenziós tömb
- Bármilyen komponens, melyben felhasználásra került az IListSource interface
- Bármilyen komponens, melyben felhasználásra került az IList interface
Mostani példánkban az egyes mezőket TextBox-okhoz kötöttük. Mivel ezek eleve szerkeszthetőek, így az adattartalom rajtuk keresztül megváltoztatható. Viszont hiába írunk bármit a TextBox-okban, az csak az aktuális DataSet-ben okoz változást, de az adatbázisunk tartalma változatlan marad. Ahhoz, hogy a végrehajtott változtatások bekerüljenek a táblába, meg kell hívnunk az SqlDataAdapter osztályunk Update függvényét, melynek paraméterül átadjuk az aktuális DataSet-et, melyben a megváltozott adatok vannak, valamint a tábla nevét, mely jelen esetben a Products lesz.
Ha viszont csak ennyit tennénk, akkor előfordulhat olyan eset, hogy a TextBox-ban épp szerkesztés alatt álló adat még nem került a DataSet-be sem, így ez nem kerül vissza az adatbázisba se, ami nyilván hibás adatrögzítéshez vezet. Történhet ez olyankor, ha az egyik TextBox-ban átírjuk az ott lévő adatot, majd rögtön az Update-t hívjuk. Ekkor az adott rekord adott mezője még szerkesztési üzemmódban van, így annak új tartalma még nem került be a DataSet-be. Elkerülendő ezt a hibát, meghívjuk még az Update előtt a ListManager EndCurrentEdit nevű függvényét, mellyel kényszerítjük, hogy a szerkesztés befejezésre kerüljön és a megváltozott tartalom mentve legyen a DataSet-be, ahonnan majd az Update hívása visszajuttatja az adattáblába.
private void button2_Click(object sender, System.EventArgs e)
{
this.BindingContext[ds, "Products"].EndCurrentEdit();
da.UpdateCommand = new SqlCommand("UPDATE Products SET ProductName = '" + textBox4.Text + "', QuantityPerUnit='"+textBox5.Text+"' WHERE (ProductID = "+label1.Text+")", connection);
da.Update(ds, "Products");
}
Ha az aktuális szerkesztést visszavonni szeretnénk, akkor használhatjuk az EndCurrentEdit helyett a CancelCurrentEdit függvényt.
Új elemet is létrehozhatunk a ListManager AddNew függvényének hívásával.
private void button5_Click(object sender, System.EventArgs e)
{
this.BindingContext[ds, "Products"].AddNew();
}
A RemoveAt függvény segítségével pedig törölhetünk egy-egy elemet a listából. Ehhez paraméterként a törlendő elem sorszámát kell megadnunk.