Lab1 Ανάπτυξη απλής εφαρµογής. Solutions, Projects, GUI, Events, Debugging. Έργα : *.vbproj (1 έργο - project) Λύση : *.sol (πολλά έργα -solution) Περιβάλλον Controls Κάθε control/στοιχείο έχει ιδιότητες (ορατές / αόρατες) ορισµένη στο χρόνο σχεδίασης µέσα στο κώδικα ώστε να γίνει ενώ το πρόγραµµα εκτελείται ιαδικασίες Οι εντολές είναι συγκεντρωµένες σε διαδικασίες π.χ. subroutines. Οι διαδικασίες εκτελούνται όταν λάβουν χώρα κάποια συµβάντα /events π.χ. το πάτηµα ενός κουµπιού. Eκτελέσιµο αρχείο *.exe debug build αυτόµατα στο bin/debug release build βελτιωµένα στο bin/release Τυχαίοι αριθµοί µεταξύ του 0..9 Label1.Text = CStr (Int (Rnd() * 10) ) Rnd() -> τυχαίος αριθµός µεταξύ του 0 και του 1 Ετοιµη Φόρµα µηνύµατος MsgBox ΚουµπίπουΠατήθηκε = MsgBox(Μήνυµα, Κουµπιά, Τίτλος) MsgBox("Your points are:" & CStr(Counter7),, "GameOver") Lab2 Ανάπτυξη user control. Χρήση διαφόρων control & libraries Eπιλογή τύπου project από το template Windows Form Control Library. Πρόσθεση standard controls στο UserControl1. π.χ. στο UserControl1 µπορεί να τοποθετηθεί ένα Textbox: Για πρόσθεση λειτουργικότητας στο UserControl1 επέµβαση στην Public κλάση του π.χ. µε επιλογή από τα events του Τextbox1 για τα συµβάντα enter και leave Public Class UserControl1 Private Sub TextBox1_Enter(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles TextBox1.Enter Me.BackColor = Color.Cyan Private Sub TextBox1_Leave(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles TextBox1.Leave Me.BackColor = Color.White End Class 1
Eλεγχος του UserControl προσθέτοντας νέo Project στην υπάρχουσα λύση: File/Add New Project /Windows form Application και επιλογή της φόρµας (Form1) του νέου project σαν Startup φόρµας αλλά και του Project as Startup Project. Βuild το UserControl1- To build process θα δηµιουργήσει ένα DLL αρχείο. Το UserControl1 συµπεριλήφθη µέσα στο Toolbox και εποµένως µπορεί να µπει πάνω στην φόρµα Form1 (Eπέµβαση στην partial κλάση του UserControl (αρχείο UserControl1.Designer.vb) Αν π.χ. στο UserControl1 σχεδιαστεί ένα Textbox: Partial Class UserControl1 Inherits System.Windows.Forms.UserControl =>ΑΛΛΑΓΗ σε Inherits System.Windows.Forms.Textbox ιαγραφή των σχετικών µε Αutosize εντολών.) Μπορούν να προστεθούν και νέες ιδιότητες επέµβαση στην Public κλάση του π.χ. ME ΕΞΙ ΚΛΙΚ (Insert Snippet) MΠΑΙΝΟΥΝ ΕΤΟΙΜΑ Patterns Στην public κλάση µπορούν να δηλωθούν µεταβλητές, ιδιότητες, ρουτίνες κ.α.. Όταν αλλάζει ο κώδικας του control πρέπει να γίνει πάλι build. Μια νέα ιδιότητα µπαίνει στο Properties Windows του control στην κατηγορία MISC (αλλά µπορεί και να αλλαχθεί η κατηγορία). Lab3 Resources organization. Database Programming ΜDI φόρµα Μέσα σε ένα project ( *.vbproj) µπορώ να προσθέσω µια ή περισσότερες νέες φόρµες(*.vb) από το επιθυµητό template. Αυτό µπορεί να γίνει από τον Solution Explorer µε κλικ στο όνοµα του Project και Add/Windows Form. Μια από αυτές τις φόρµες θα είναι η πρώτη του έργου (Startup form). Αυτό µπορεί να γίνει και από τον Solution Explorer µε κλικ στο όνοµα του Project και Properties/Application/StartupForm. Το template µιας φόρµας µπορεί να είναι π.χ. (Common Items/) Windows Application Form Mdi Parent Form Control Splash Screen κ.α. 2
H Mdi φόρµα έχει την ιδιότητα ΙsMdiContainer true και έχει και ένα έτοιµο MenuStrip, που µπορεί να αλλαχθεί µε το βελάκι: smart-tag glyph ( )) -στα περισσότερα control υπάρχει αυτό το βελάκι. Με το που φορτώνεται η MDIparent φόρµα µπορούν να τις ανατεθούν τα παιδιά της πχ. Form1.MdiParent = Me Form2.MdiParent = Me... (αν Form1, Form2 είναι Children). Προσπέλαση των children της MDIParent1 φόρµας: For Each frm In My.Forms.MDIParent1.MdiChildren Next Σύνδεση µε βάση Αccess Για να χρησιµοποιήσουµε µια υπάρχουσα Αccess Βάση εδοµένων στο πρόγραµµά µας µπορούµε να προσθέσουµε ένα dataset µέσω του µενού Data / Add New Data Source και µέσω Wizard στην επιλογή Νew Connection να δώσουµε το path που βρίσκεται η βάση (να το τεστάρουµε) και αν θέλουµε να την αντιγράψουµε και µέσα στο project µας. Στο dataset επιλέγουµε τους επιθυµητούς πίνακες και τα πεδία που θέλουµε να έχουµε. Στο dataset.xsd φαίνεται αι το σχήµα που επιλέξαµε µε τους πίνακεςτα πεδία τους και τις σχέσεις µεταξύ τους. Σε µια φόρµα τώρα µπορούµε να βάλουµε ένα πίνακα του dataset (από το παράθυρο Data Sources) είτε σε Details είτε σε DataGridView. Επιλέγουµε συνήθως το Details. Oταν όµως έχουµε δυο πίνακες που συνδέονται, τον πρώτο πίνακα-master- σε Details τον δεύτερο πίνακα-details- σε DataGridView). Όταν ένας πίνακας π.χ. Categories µπει πάνω σε µια φόρµα στο Components tray θα δηµιουργηθούν τα ακόλουθα components: CategoriesBindingSource CategoriesTableAdapter NorthwindDataSet TableAdapterManager ProductsBindingNavigator Όταν ένας δεύτερος πίνακας π.χ. Products µπει πάνω σε µια φόρµα στο Components tray θα δηµιουργηθούν µόνο τα: ProductsBindingSource ProductsTableAdapter Αν θέλουµε οι δυο πίνακεςνα συνδέονται θα πρέπει ο δεύτερος πίνακας να επιλεχθεί από την συλλογή του πρώτου (αυτό είναι ουσιαστικά το πεδίο που τους ενώνει) 3
Η εντολή που µπορεί να εκτελεστεί µε το που φορτώνεται µια φόρµα, είναι να γεµίσουν (Fill) τα πεδία των πινάκων της φόρµας π.χ. Me.CategoriesTableAdapter.Fill(Me.NorthwindDataSet.Categories) Me.ProductsTableAdapter.Fill(Me.NorthwindDataSet.Products) Πρώτα ο master και µετά ο detail πίνακας Lab4 Database Programming PostgreSQL Για να συνδέουµε µια PostgreSQL Βάση εδοµένων στο πρόγραµµά µας, πρέπει να εγκαταστήσουµε τα: pgadmin3-1.8.4 (pgadmin3.msi) psqlodbc_09_00_0101.zip (psqlodbc.msi) createnorth (create.sql σκριπτάκι που δηµιουργεί την Νorthwind στην PostgreSQL & triggers.sql) Κατόπιν στο Αdd New Data Sources/Database/Dataset/New Connection στο DataSource επιλέξτε Change για να αλλάξτε από την Microsoft Access (που είχατε) σε ΟDBC έτσι επιλέξτε Μicrosoft ODBC Data Source. Στο DatαSource Specification /Use user or system data source επιλέξτε PostgreSQL35W και ελέγξτε την σύνδεση σας µε Τest Connection. Επιλέξτε τον DataSet Designer. Παρατηρήστε ότι δεν υπάρχουν οι σχέσεις µεταξύ των πινάκων και βάλτε τις (επιλέγοντας τα επιθυµητό πεδία και σύροντας το ποντίκι ή µε Αdd/Relation). O adapter του πίνακα π.χ. Categories γεµίζει fill- τον πίνακα µε µια query της µορφής SELECT CategoryID, CategoryName, Description FROM ade504.categories Εστω ότι θέλουµε να γίνει αναζήτηση κατηγορίας µε κριτήρια παραµετρικά (που δίνονται από τον χρήστη). Θα φτιάξουµε µια query έστω FillByCompanyName SELECT CategoryID, CategoryName, Description FROM ade504.categories ( WHERE CategoryName LIKE?) Το κτίσιµο της νέας query γίνεται στον adapter µε add/query Κάθε νέα query εµφανίζεται στο σχήµα, στην περιοχή του adapter κάτω από την query Fill. Η προεπειλεχθείσα Fill µπορεί να αλλαχθεί όταν φορτώνεται η φόρµα µε την FillByCompanyName ώστε να δώσει όλες τις κατηγορίες που στο όνοµα περιέχουν π.χ. καποιο γράµµα έστω το e Me.CategoriesTableAdapter.FillByCompanyName(Me.Adelab5DataSet.Categories, "%e%") Στο σχήµα µπορεί να προστεθεί νέος TableAdapter (µε δεξί κλικ) και εποµένως νέος πίνακας στο dataset µας. 4
Lab5 Data Validation FORM LEVEL VALIDATION - DATA LEVEL VALIDATION - σε επίπεδο φόρμας σε επίπεδο dataset Validation σε επίπεδο φόρµας. O έλεγχος σωστής εισαγωγής σε ένα Textbox1 γίνεται με το event Validating: Private Sub ΤextBox1_Validating( ByVal sender As Object,ByVal e As _ System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating If ΤextBox1.Text = String.Empty OrElse Not Decimal.TryParse(ΤextBox1.Text, 0D) Then 0Decimal MessageBox.Show("Please enter a price", "Products", MessageBoxButtons.OK, MessageBoxIcon.Error) e.cancel = True Return If Convert.ToDecimal(ΤextBox1.Text) <= 0 Then MessageBox.Show("Price must be higher than 0", "Products", MessageBoxButtons.OK, MessageBoxIcon.Error) e.cancel = True Έλεγχος σωστών δεδομένων σε μια φόρμα με το event FormClosing για την περίπτωση που κλείνουμε την φόρμα χωρίς να πατηθεί το SAVE. Private Sub Form1_FormClosing(ByVal sender As System.Object, ByVal e As _ System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing If ValidateData() Then If Me.NorthwindDataSet.Products.GetChanges IsNot Nothing Then Dim response As Integer response =MessageBox.Show("Do you want to save your changes?", _ "Changes have been made", MessageBoxButtons.YesNoCancel, _ MessageBoxIcon.Warning) If response = DialogResult.Yes Then If SaveChanges() Then MessageBox.Show("Your changes were saved", "Products", _ MessageBoxButtons.OK) Else e.cancel = True ElseIf response = DialogResult.Cancel Then e.cancel = True Private Function ValidateData() As Boolean If Me.Validate() Then Try Me.ProductsBindingSource.EndEdit() Return True 5
Catch ex As Exception If MessageBox.Show("Invalid data was entered. Cancel edits?", _,MessageBoxButtons.YesNo,MessageBoxIcon.Error) = _ DialogResult.Yes Then ProductsBindingSource.CancelEdit() Return False End Try Return False End Function Private Function SaveChanges() As Boolean If ValidateData() Then If ReorderLevelTextBox.Text <> String.Empty Then If Convert.ToDecimal(UnitPriceTextBox.Text) > 25 And _ Convert.ToInt32(ReorderLevelTextBox.Text) > 100 Then MessageBox.Show("Products that cost more than $25 " & _ "must have a reorder level below 100","Products", _ MessageBoxButtons.OK,MessageBoxIcon.Information) Return False Me.TableAdapterManager.UpdateAll( Me.NorthwindDataSet) Return True Return False End Function Το Validation σε επίπεδο DATASET, γίνεται χρησιµοποιώντας τα events των DataTables TableNewRow, ColumnChanging - RowChanging και βάζοντας τον ΕrrorProvider πάνω στην φόρµα Partial Class NorthwindDataSet Partial Class ProductsDataTable Private Sub ProductsDataTable_ColumnChanging(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs) Handles Me.ColumnChanging If e.column.columnname = "UnitPrice" Then If Convert.ToDecimal(e.ProposedValue) <= 0 Then e.row.setcolumnerror(e.column, _ "Please enter a price greater than $0.") Else e.row.setcolumnerror(e.column, String.Empty) Private Sub ProductsDataTable_ProductsRowChanging( ByVal sender As Object, ByVal e As ProductsRowChangeEvent) Handles Me.ProductsRowChanging 6
If e.row.rowstate <> DataRowState.Deleted Then If e.row.unitprice > 25 And e.row.reorderlevel > 100 Then e.row.rowerror ="Products that cost more than $25 must " & "have a reorder level below 100" Else e.row.clearerrors() Private Sub ProductsDataTable_TableNewRow(ByVal sender As Object, ByVal e As System.Data.DataTableNewRowEventArgs) Handles Me.TableNewRow End Class Dim productrow As NorthwindDataSet.ProductsRow = _ CType(e.Row, NorthwindDataSet.ProductsRow) productrow.discontinued = False Κάθε πίνακας έχει την ΗasErrors property. Κάθε γραµµή- εγγραφή ενός πίνακα έχει την RowError property. Private Function DataHasErrors() As Boolean Dim errorstring As New System.Text.StringBuilder If Me.NorthwindDataSet.Products.HasErrors Then For Each row As DataRow In Me.NorthwindDataSet.Products If row.haserrors Then errorstring.append(row.rowerror & vbcrlf) Next MessageBox.Show( "The following errors occurred: " & vbcrlf & vbcrlf & errorstring.tostring,"products", MessageBoxButtons.OK, MessageBoxIcon.Error) Return True Return False End Function Private Function SaveChanges() As Boolean If ValidateData() Then If Not DataHasErrors() Then Me.TableAdapterManager.UpdateAll( Me.NorthwindDataSet) Return True Return False End Function Ο αρχικός κώδικας του Save button µε τις τρεις µεθόδους: Validate, EndEdit και UpdateAll, θα αντικατασταθεί µε την function SaveChanges: 7
Private Sub ProductsBindingNavigatorSaveItem_Click(ByVal sender As _ System.Object,ByVal e As System.EventArgs) Handles _ ProductsBindingNavigatorSaveItem.Click If SaveChanges() Then MessageBox.Show("Your changes were saved", "Products", MessageBoxButtons.OK) Lab6 Project Properties / Publishing the application Project Properties Mε διπλό κλικ στο MyProject καθορίζεις τις properties του project χωρισµένες ανά κατηγορίες: που είναι 1 η κατηγορία Αpplication StartupForm Assembly Information στο AssemblyInfo.vb file Splash Screen View Application Events στο ApplicationEvents.vb file Startup (Τι γίνεται πριν ξεκινήσει η εφαρµογή, αρχικοποίηση µεταβλητών..) Shutdown (Τι γίνεται πριν τελειώσει η εφαρµογή, σώσιµο µεταβλητών, resources..) 2 η κατηγορία Compile Configuration : κατάσταση / χτίσιµο του project release or debug, (active, all configurations) Compile Options (Explicit, Strict, Ιnfer) Warning Configuration Advanced Compile Options Ορισµός Customs Constants Build Events Τι γίνεται πριν και µετά το στήσιµο του project Publishing Publish Wizard (Build/Publish) Publish page (Project properties/publish tab) Η εφαρµογή κατόπιν µπορεί να εγκατασταθεί είτε Online (χωρίς shortcut ) Offline (µε shortcut στο Start menu) 8
Lab7 Namespaces (My.Application, My.Computer, others) My.Application. OpenForms. MinimumSplashScreenDisplayTime My.Application. Info. AssemblyName. Info.Title My.Computer. Screen. Bounds.Screen.WorkingArea My.Computer. FileSystem.CurrentDirectory. FileSystem.FileExists. FileSystem.DirectoryExists My.Computer. Keyboard.CapsLock.Keyboard.NumLock My.Computer. Network.isAvailable.Network.DownloadFile My.Settings.MεταβλητήπουΟρίσαµε For Each frm As Form In My.Application.OpenForms... Next Imports System.IO For Each drv As DriveInfo In My.Computer.FileSystem.Drives... Next Lab8 Files and Folders SQL s queries Dialog Controls: OpenFileDialog, SaveFileDialog,FolderBrowserDialog If (OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK) Then MsgBox( File name given: & OpenFileDialog1.Filename ) Ανάγνωση αρχείου κειµένου γραµµή γραµµή Imports System.IO Bάζοντας τις γραµµές του αρχείου σε ένα listbox Dim lfile As String = "C:\Documents and Settings\All Users\allfiles.txt" Try ' Create an instance of StreamReader to read from a file. 9
Dim SR As StreamReader = New StreamReader(lfile) Dim str As String 'Read and display in a Listbox1 until the end of the file Do str = SR.ReadLine If Not str = String.Empty Then ListBox1.Items.Add(str) Loop Until str Is Nothing SR.Close() Catch ex As Exception MsgBox("Reading file error... " + vbcrlf + ex.message()) End Try sr.close() ή βάζοντας τις γραµµές του αρχείου σε ένα textbox Do Until sr.endofstream 'read lines from file LineOfText = sr.readline() 'add each line to the AllText variable AllText = AllText & LineOfText & vbcrlf Loop TextBox1.Text = AllText 'display file ηµιουργία αρχείου κειµένου µε στοιχεία από πίνακα του Dataset Imports System.IO Dim sw As StreamWriter sw = File.CreateText(SaveFileDialog1.FileName) Dim str As String For Each dr As DataRow In NorthwindDataSet.Tables("Customers").Rows str= dr("companyname").tostring () sw.writeline(str) Next sw.close() To αρχείο µε όνοµα "c:\test\onoma.txt" µπορεί να δηµιουργηθεί και µε την παρακάτω εντολή sw = File.CreateText("c:\test\onoma.txt") Προσπέλαση σε ένα πίνακα του dataset: NorthwindDataSet.Tables(0) ή NorthwindDataSet.Tables ("Categories") ή NorthwindDataSet.Categories Προσπέλαση σε γραµµή πίνακα: NorthwindDataSet.Tables("Categories").Rows(5) '6 η γραµµή Προσπέλαση σε στοιχείο γραµµής πίνακα: NorthwindDataSet.Tables("Categories").Rows(5).Item(1) ή NorthwindDataSet.Tables("Categories").Rows(5).Item("CategoryName") '6 η γραµµή,categoryname Π.χ. 10
For Each r As DataRow In NorthwindDataSet.Categories.Rows ' process Categories Row r: ' r.item("categoryname") ' r.item("description"),and so on Next SQL s queries Action queries ( INSERT,DELETE,UPDATE ) DELETE Customers WHERE Country IS NULL DELETE Orders WHERE OrderDate < 1/1/1998 INSERT Customers (CustomerID, CompanyName) VALUES ( Cust1, Company A ) INSERT INTO SelectedProducts SELECT * FROM Products WHERE CategoryID = 4 UPDATE Customers SET Country= United Kingdom WHERE Country = UK Aggregate/scalar queries (SELECT COUNT(),SUM(),AVG(),MIN(),MAX() ) SELECT COUNT(CustomerID) FROM Customers WHERE Country = Germany SELECT SUM(Quantity * UnitPrice * (1 - Discount)) FROM [Order Details] WHERE ProductID = 11 SELECT SUM(Quantity), SUM(Quantity * UnitPrice * (1 - Discount)) FROM [Order Details] WHERE ProductID = 11 Select queries ( SELECT ) SELECT DISTINCT CompanyName FROM Customers WHERE Country = Germany SELECT * FROM Products WHERE UnitPrice IS NULL SELECT CompanyName, ContactName, Country, City FROM Customers ORDER BY Country, City SELECT Orders.OrderID, [Order Details].ProductID,[Order Details].UnitPrice,[Order Details].Quantity (1 - [Order Details].Discount) AS SubTotal FROM Orders INNER JOIN [Order Details] ON Orders.OrderID = [Order Details].OrderID SELECT CompanyName FROM Customers WHERE Country IN ( Germany, Austria, Switzerland ) SELECT OrderID, OrderDate, CompanyName FROM Orders WHERE (OrderDate BETWEEN 1/1/1997 AND 12/31/1997 ) Παρακάτω εισάγεται µια γραµµή στον πίνακα Categories µέσω του CategoriesTableAdapter - φυσικά αν δηµιουργεί duplicate values δεν γίνεται εισαγωγή 11
Dim LineofText As String ="Katigoria9,Perigrafi9" Dim P As Array = LineofText.Split(",") 'P(0)="Katigoria9" P(1)="Perigrafi9" Try Me.CategoriesTableAdapter.Insert(P(0), P(1), Nothing) Catch ex As Exception MsgBox(ex.Message()) End Try ηµιουργία directory Dim dir As DirectoryInfo = New DirectoryInfo("c:\MyDir") Try ' Determine whether the directory exists. If dir.exists Then MsgBox("That path exists already.") Return 'Create the directory. dir.create() MsgBox("The directory was created successfully.") Catch ex As Exception MsgBox(String.Format("Create process failed: {0}", _ ex.tostring())) End Try Lab9 Threads Imports System.Threading για την Thread.Sleep(100) Βάζουµε πάνω στην φόρµα ένα BackgroundWorker Component - µπαίνει στο component tray. Κάνουµε true τις παρακάτω ιδιότητες του BackgroundWorker1.WorkerSupportsCancellation = True BackgroundWorker1.WorkerReportsProgress = True Για να ξεκινήσει 2 ο thread δίνω την εντολή: BackgroundWorker1.RunWorkerAsync() Για να σταµατήσει BackgroundWorker1.CancelAsync() Προγραµµατίζουµε τα events του ανάλογα το τι θα κάνει το thread και στέλνουµε και ReportProgress ώστε ανάλογα την πρόοδο να κάνει κάτι στο ProgressChanged Private Sub BackgroundWorker1_DoWork( )... BackgroundWorker1.ReportProgress(work) Private Sub BackgroundWorker1_ProgressChanged( ) Private Sub BackgroundWorker1_RunWorkerCompleted( ) 12