|  | Unser Angebot für Sie! Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'! |
| | | | | |
Adressverwaltung mit .NET, Teil 2
Manfred Hoffbauer, Düsseldorf
Im ersten Teil dieses Beitrags haben Sie die Adressen aus einer Access-Datenbank in ein DataGrid-Steuerelement geladen. In diesem zweiten Teil steigen Sie tiefer in die Programmierung ein und erfahren, wie Sie Adressen aus einem Listensteuerelement auswählen und komfortabel in der Einzelansicht bearbeiten können.
Ein Formular für Adressen
Die folgenden Beispiele und Vorgehensweisen können Sie mit der kostenlosen Entwicklungsumgebung SharpDevelop nachvollziehen. Alternativ lässt sich der Programmcode natürlich auch in einem Microsoft-Visual-Studio.NET-Projekt verwenden.
Das Ziel dieses Beitrags ist ein Formular zur Eingabe und Bearbeitung von Adressen. Es enthält ein Listenfeld mit einer Übersicht der Adressen. Jede einzelne Adresse kann mit der Maus angeklickt und bearbeitet werden. Auch das Hinzufügen und Löschen von Adressen ist implementiert. Das Formular soll wie in Abb. 1 aussehen.

Abb. 1: Formular zur Eingabe und Bearbeitung von Adressen
Zur Eingabe und Bearbeitung der Adressen legen Sie ein Formular mit Einzelsatzansicht an. Gehen Sie dazu wie folgt vor:
Wählen Sie den Menüpunkt Datei ( Neu ( Combine aus der Menüzeile.
Wählen Sie ein Verzeichnis für das neue Projekt aus.
Geben Sie WinAdress2 als Dateinamen für das neue Projekt ein.
Markieren Sie die Schablone Windows-Anwendung.
Klicken Sie auf Erstellen. (
Das Formular benennen
SharpDevelop generiert den Programmcode für ein neues, leeres Formular und speichert ihn unter dem Namen MainForm.vb. Mit den Registern Quellcode und Design wechseln Sie zwischen der Ansicht des Programmcodes und der Anzeige des Formularentwurfs.
Um den Namen des Formulars zu ändern, gehen Sie wie folgt vor:
Wechseln Sie in die Design-Ansicht des Formulars.
Klicken Sie mit der rechten Maustaste auf einen leeren Bereich des Formulars.
Wählen Sie den Menüpunkt Eigenschaften aus dem Kontextmenü.
Um die Titelzeile des Formulars zu ändern, geben Sie für die Eigenschaft Text den Wert Adressen ein.
Ändern Sie die Eigenschaft Name des Formulars auf frmAdressen. (
Beachten Sie, dass Sie mit dem Eigenschaftenfenster nur die Name-Eigenschaft des Formulars und die Titelzeile ändern können. SharpDevelop speichert den Programmcode weiterhin in der Datei MainForm.vb. Um den Namen der Formulardatei zu ändern, gehen Sie wie folgt vor:
Klicken Sie im unteren Register des SharpDevelop-Fensters auf die Lasche Projekte.
Klicken Sie im Projekt-Explorer auf den Eintrag MainForm.vb.
Betätigen Sie die Taste F2 und benennen Sie die Datei in frmAdressen.vb um. (
Der ursprüngliche Name MainForm kommt jetzt immer noch als Klassenname innerhalb des Quellcodes vor. Falls Sie auch dies noch ändern wollen, müssen Sie die Zeile
Public Class MainForm
in
Public Class Adressen
umwandeln. Außerdem müssen Sie die Prozedur anpassen, die das Startformular der Anwendung instanziert:
Public Shared Sub Main
Dim fAdressen As New Adressen
fAdressen.ShowDialog()
End Sub
Steuerelemente anordnen
Das Formular soll ein ListView-Steuerelement erhalten, das eine Liste aller Adressen anzeigt. Um die Liste anzulegen, klicken Sie am linken unteren Rand des SharpDevelop-Fensters auf die Registerlasche Tools. Markieren Sie in der Toolbox die Gruppe Windows Forms. Ziehen Sie dann das ListView-Steuerelement auf den Entwurfsbereich. Im Eigenschaftenfenster sollten Sie den Namen des Steuerelements auf lstvAdressen ändern.
Die weiteren Eigenschaften des ListView-Steuerelements können Sie so lassen wie sie sind. Sie werden später per Programmcode verändert. Zur Anzeige der Adressen in der Einzelansicht benötigen Sie die Label-Steuerelemente aus Tab. 1.
Label-Name |
Text |
lblAnrede |
Anrede |
lblVorname |
Vorname |
lblNachname |
Nachname |
lblStrasse |
Strasse |
lblPlzOrt |
PLZ/Ort |
lblTelefon |
Telefon |
lblTelefax |
Telefax |
Tab. 1: Diese Label-Steuerelemente sind erforderlich.
Die Anzeige und Bearbeitung der Daten erfolgt in Text- und Kombinationsfeldern. Tab. 2 enthält eine Übersicht der erforderlichen Steuerelemente.
Name |
Steuerelementtyp |
cmbAnredeID |
ComboBox |
txtVorname |
TextBox |
txtNachname |
TextBox |
txtStrasse |
TextBox |
txtPLZ |
TextBox |
txtOrt |
TextBox |
txtTelefon |
TextBox |
txtTelefax |
TextBox |
Tab. 2: Diese Kombinations- und Textfelder sind erforderlich.

Abb. 2: Die Abbildung zeigt die Steuerelemente zur Anzeige und Bearbeitung von Adressen.
Das Hinzufügen der Steuerelemente erfolgt über die Toolbox. Ordnen Sie die Steuerelemente stets paarweise so an, dass eine Einzelsatzansicht wie in Abb. 2 entsteht.
Zum Test können Sie das Programm per F5-Taste starten. Sie werden dabei feststellen, dass es vollständig kompiliert und ausgeführt werden kann. Nur das Ergebnis ist vielleicht etwas ernüchternd. Sie erhalten ein Formular völlig ohne Funktionalität, das noch nicht einmal einen Datensatz anzeigen kann. Dies verdeutlicht einen wichtigen Unterschied zwischen Microsoft Access und einem .NET-Programm: Bei .NET müssen Sie jede einzelne Programmfunktion selbst programmieren. Wenn Sie also einen Datensatz anzeigen wollen, dann benötigen Sie zunächst einmal ein Programm, das per OleDB auf eine Access-Datenbank zugreift.
Data Layer
Die Routinen für den Datenzugriff sollen in der Klasse DataLayer zusammengefasst werden.
Zum Anlegen der Klasse gehen Sie wie folgt vor:
Wählen Sie den Befehl Ansicht/Projekte aus der Menüzeile.
Klicken Sie mit der rechten Maustaste auf das Projekt WinAdress2.
Wählen Sie den Befehl Hinzufügen/Neue Datei aus dem Kontextmenü.
Markieren Sie in dem sich öffnenden Dialog die Kategorie VB und die Schablone Klasse.
Geben Sie DataLayer als Namen der Klasse ein.
Klicken Sie auf die Schaltfläche Erstellen. (
SharpDevelop erzeugt darauf eine neue Klassendatei und fügt diese dem aktuellen Projekt hinzu. Sie ersetzen den Programmcode vollständig durch eigenen Programmcode. Mit der ersten Anweisung importieren Sie den Namenspace System.Data.OleDb. Im Beitrag ADO.NET - eine Einführung in Ausgabe 5/2004 von Access im Unternehmen finden Sie weitere Details zum Namespace OleDb. Er enthält auf jeden Fall die für den Datenzugriff benötigten Objekte.
Die Prozedur New ist der Konstruktor der Klasse DataLayer. Der enthaltene Programmcode wird immer dann ausgeführt, wenn Sie ein neues Objekt dieser Klasse instanzieren. Der Konstruktor ist so definiert, dass die aufrufende Anweisung immer einen ConnectionString angeben muss. Die New-Prozedur weist den String einer Variablen zu, die von allen Methoden der Klasse verwendet werden kann.
Die DataLayer-Klasse implementiert das IDisposable-Interface. Die Implementation befindet sich in der Dispose()-Klasse. Sie schließt die Connection. Mit dieser Art der Implementierung erreichen Sie, dass die Connection per Dispose() von einer aufrufenden Methode und automatisch von der .NET-Runtime-Umgebung aufgerufen werden kann. Durch die Prüfung Not m_Cnn Is Nothing ist in jedem Fall sichergestellt, dass die Connection nur einmal geschlossen wird.
Imports System.Data.OleDb
Public Class DataLayer
Implements System.IDisposable
Dim m_CnnString As String
Dim m_Cnn As OleDbConnection
Public Sub New(ByVal ConnectionString As String)
m_CnnString = ConnectionString
End Sub
Public Sub Dispose()
Implements System.IDisposable.Dispose
If Not m_Cnn Is Nothing Then
m_Cnn.Close()
m_Cnn.Dispose()
m_Cnn = Nothing
End If
End Sub
Private Function OpenConnection() As OleDbConnection
If m_Cnn Is Nothing Then
m_Cnn = New OleDbConnection(m_CnnString)
m_Cnn.Open()
End If
End Function
Quellcode 1
Public Function GetAnreden() As DataTable
OpenConnection()
Dim tblAnreden As New DataTable
Dim sb As New System.Text.StringBuilder
sb.Append("SELECT tblAnreden.* FROM tblAnreden ")
Dim adp As New OleDbDataAdapter(sb.ToString(), _ m_Cnn)
adp.Fill(tblAnreden)
adp.Dispose()
Return tblAnreden
End Function
Quellcode 2
Die Funktion OpenConnection öffnet die Connection zu einer Access-Datenbank (s. Quellcode 1). Der Rückgabewert der Funktion ist das geöffnete OleDbconnection-Objekt.
Daten lesen
Auf der Basis des Connection-Objekts können die DataLayer-Funktionen direkt auf die Tabellen der Access-Datenbank zugreifen. Die Funktion GetAnreden öffnet die Connection (s. Quellcode 2). Das StringBuilder-Objekt ist ein performanter Weg für den Zusammenbau von Zeichenketten. Die Append-Methode fügt ganz einfach den als Parameter übergebenen String an die bestehende Zeichenkette an. Die so zusammengesetzte SELECT-Anweisung kann zum Auffüllen eines DataAdapter-Objekts verwendet werden. Die Rückgabe der gelesenen Anreden erfolgt in Form eines DataTable-Objekts.
Die GetAdressen-Funktion funktioniert genauso wie die GetAnreden-Funktion. Nur die SELECT-Anweisung ist etwas aufwändiger (s. Quellcode 3). Sie stellt eine relationale Beziehung zwischen tblAdressen und tblAnreden her. Das entstehende DataTable-Objekt enthält zusätzlich zu den Adressen ein Feld für die Anrede.
Adressen anlegen, ändern und löschen
Die AddAdress-Funktion verwendet ebenfalls ein StringBuilder-Objekt zur Bildung einer SQL-Anweisung (s. Quellcode 4). In diesem Fall handelt es sich um eine INSERT-INTO-Anweisung, die die Anlage eines neuen Datensatzes ermöglicht. Die Parameterliste der Funktion enthält eine Variable für jedes Feld, das an die tblAdressen-Tabelle angefügt werden soll.
Eine Besonderheit ist das Feld AnredeID. Wenn es den Wert 0 hat, dann soll dies als "keine Anrede" interpretiert werden. In diesem Fall fügt die AddAdress-Funktion einen NULL-Wert in die Tabelle ein.
Auf die AddAdress-Funktion folgen die UpdateAddress- und die DeleteAdress-Funktionen.
Public Function GetAdressen() As DataTable
OpenConnection()
Dim tblAdressen As New DataTable
Dim sb As New System.Text.StringBuilder
sb.Append("SELECT tblAdressen.*, tblAnreden.Anrede FROM tblAnreden ")
sb.Append("RIGHT JOIN tblAdressen ON tblAnreden.AnredeID = tblAdressen.AnredeID;")
Dim adp As New OleDbDataAdapter(sb.ToString(), m_Cnn)
adp.Fill(tblAdressen)
adp.Dispose()
Return tblAdressen
End Function
Quellcode 3
Public Function AddAdress(ByVal AnredeID As Integer, ByVal Vorname As String, _
ByVal Nachname As String, ByVal Strasse As String, ByVal PLZ As String, _
ByVal Ort As String, ByVal Telefon As String, ByVal Telefax As String) As Int32
Dim sb As New System.Text.StringBuilder
sb.Append("INSERT INTO tblAdressen ")
sb.Append("(AnredeID, Vorname, Nachname, Strasse, PLZ, Ort, Telefon, Telefax) ")
sb.Append("VALUES (")
If AnredeID = 0 Then
sb.Append("NULL, ")
Else
sb.Append(AnredeID.ToString() + ", ")
End If
sb.Append(Quote(Vorname) + ", ")
sb.Append(Quote(Nachname) + ", ")
sb.Append(Quote(Strasse) + ", ")
sb.Append(Quote(PLZ) + ", ")
sb.Append(Quote(Ort) + ", ")
sb.Append(Quote(Telefon) + ", ")
sb.Append(Quote(Telefax) + ") ")
Execute(sb)
End Function
Quellcode 4
Sie setzen ebenfalls SQL-Anweisungen zusammen, die dann per Execute-Methode zur Ausführung gelangen (s. Quellcode 5 und 6).
Die Execute-Methode erhält ein auszuführendes SQL-Statement als StringBuilder-Objekt übergeben (s. Quellcode 7). Für die Ausführung des Objekts wird ein neues OleDbCommand-Objekt basierend auf der geöffneten DataLayer-Connection instanziert. Die ExecuteNonQuery-Methode führt die Aktualisierungsabfrage aus.
Die Quote-Funktion (s. Quellcode 8) ist bei der Bildung der SQL-Anweisungen erforderlich. Sie klammert einen String in Apostrophe. Falls der String bereits ein Apostroph enthält, wird es durch zwei aufeinander folgende Apostrophe ersetzt.
Daten anzeigen
Die verschiedenen Methoden des Formulars teilen sich einige Variablen und eine Auflistung. Um diese Variablen zu definieren, sollten Sie unterhalb von
Public Function UpdateAdress(ByVal row As DataRow, ByVal AnredeID As Integer, _
ByVal Vorname As String, ByVal Nachname As String, ByVal Strasse As String, _
ByVal PLZ As String, ByVal Ort As String, ByVal Telefon As String, _
ByVal Telefax As String) As Int32
If (Not row Is Nothing) Then
Dim AdressID As Integer
AdressID = CInt(row.Item("AdressID"))
Dim sb As New System.Text.StringBuilder
sb.Append("UPDATE tblAdressen SET ")
If AnredeID = 0 Then
sb.Append("tblAdressen.AnredeID = NULL, ")
Else
sb.Append("tblAdressen.AnredeID = " + AnredeID.ToString() + ", ")
End If
sb.Append("tblAdressen.Vorname = " + Quote(Vorname) + ", ")
sb.Append("Nachname = " + Quote(Nachname) + ", ")
sb.Append("Strasse = " + Quote(Strasse) + ", ")
sb.Append("PLZ = " + Quote(PLZ) + ", ")
sb.Append("Ort = " + Quote(Ort) + ", ")
sb.Append("Telefon = " + Quote(Telefon) + ", ")
sb.Append("Telefax = " + Quote(Telefax) + " ")
sb.Append("WHERE AdressID = " + AdressID.ToString())
Execute(sb)
End If
End Function
Quellcode 5
Public Sub DeleteAdress(ByVal row As DataRow)
If (Not row Is Nothing) Then
Dim AdressID As Integer
AdressID = CInt(row.Item("AdressID"))
Dim sb As New System.Text.StringBuilder
sb.Append("DELETE FROM tblAdressen ")
sb.Append("WHERE AdressID = " + AdressID.ToString())
Execute(sb)
End If
End Sub
Quellcode 6
Public Class Adressen
Inherits System.Windows.Forms.Form
die folgenden Anweisungen einfügen:
Private m_ConnectionString As String
Private m_DataLayer As DataLayer
Private m_Modus As Modus
Private Enum Modus
Update
Insert
Null
End Enum
Die Variable m_ConnectionString speichert den ConnectionString; die Variable m_DataLayer bevorratet das DataLayer-Objekt, das von allen Methoden des Formulars verwendet werden kann. Die Variable m_Modus gibt Auskunft darüber, ob der Anwender gerade einen Datensatz anfügt oder aktualisiert.
Private Sub Execute(ByVal sb As System.Text.StringBuilder)
Dim cmd As OleDbCommand
cmd = New OleDbCommand(sb.ToString, m_Cnn)
cmd.ExecuteNonQuery()
cmd.Dispose()
End Sub
Quellcode 7
Private Function Quote(ByVal str As String)
Return "'" & Microsoft.VisualBasic.Replace(str, "'", "''") & "'"
End Function
End Class
Quellcode 8
Private Sub FrmAdressenLoad(sender As System.Object, e As System.EventArgs)
m_ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" + System.Environment.CurrentDirectory + "\Adress00.mdb"
m_DataLayer = New DataLayer(m_ConnectionString)
Me.cmbAnredeID.DataSource = m_DataLayer.GetAnreden()
Me.cmbAnredeID.ValueMember = "AnredeID"
Me.cmbAnredeID.DisplayMember = "Anrede"
SetListViewProperties()
AddHeader()
ShowData()
End Sub
Quellcode 9
Die Load-Ereignisprozedur
Beim Öffnen des Formulars muss als Erstes das ListView-Steuerelement mit den Adressdaten gefüllt werden. Dazu sind folgende Schritte erforderlich:
Die Datenherkunft des Kombinationsfeldes cmbAnredeID auf eine Liste der Anrede setzen.
Dem ListView-Steuerelement muss eine Liste der Überschriften zugewiesen werden.
Die Adressendaten müssen im ListView-Steuerelement angezeigt werden.
Zur Durchführung dieser Aufgaben wechseln Sie in die Entwurfsansicht des Formulars. Klicken Sie doppelt auf einen leeren Bereich des Formulars, damit SharpDevelop den Prozedurrumpf für das Load-Ereignis einfügt.
Um das Load-Ereignis zu implementieren, fügen Sie den folgenden Programmcode in den Prozedurrumpf ein (s. Quellcode 9).
Die erste Anweisung definiert den ConnectionString für den Zugriff auf die Adressdatenbank. Es handelt sich hierbei um die Beispieldatenbank Adress00.mdb, die schon in verschiedenen Beiträgen dieses Werks verwendet wurde.
Das Programm erwartet die Datenbank in dem Verzeichnis, aus dem es gestartet wird. Anders gesagt: Sie sollten die Datenbank im gleichen Verzeichnis wie die EXE-Datei ablegen oder Sie passen den ConnectionString an das entsprechende Verzeichnis an.
Der Variablen m_DataLayer wird eine Instanz der DataLayer-Klasse zugewiesen. Diese Instanz wird für alle Datenzugriffe des Formulars verwendet.
Private Sub SetListViewProperties()
With lstvAdressen
.View = View.Details
.LabelEdit = False
.AllowColumnReorder = True
.CheckBoxes = False
.FullRowSelect = True
.GridLines = True
.Sorting = SortOrder.None
.Activation = ItemActivation.Standard
.HideSelection = False
.MultiSelect = False
.HoverSelection = False
End With
End Sub
Quellcode 10
Private Sub AddHeader()
With lstvAdressen.Columns
.Add("Anrede", 50, HorizontalAlignment.Left)
.Add("Vorname", 80, HorizontalAlignment.Left)
.Add("Nachname", 80, HorizontalAlignment.Left)
.Add("Strasse", 80, HorizontalAlignment.Left)
.Add("PLZ", 50, HorizontalAlignment.Left)
.Add("Ort", 80, HorizontalAlignment.Left)
End With
End Sub
Quellcode 11
Die Zuweisung von AnredeID an die Eigenschaft ValueMember des Steuerelements cmbAnredeID bewirkt, dass sich der Wert des Steuerelements durch den Wert des Feldes AnredeID definiert. Falls Sie also die Anrede Frau aus der Liste auswählen und Frau die AnredeID 5 hat, dann erhält das Kombinationsfeld den Wert 5. Die Eigenschaft DisplayMember definiert den Namen der in der Liste Kombinationsfeldes anzuzeigenden Spalte. Sowohl der ValueMember als auch der DisplayMember müssen in der Datenherkunft des Kombinationsfeldes vorhanden sein. Die Datenherkunft selbst wird mit der DataSource-Eigenschaft an die Tabelle tblAnreden gebunden.
Eigenschaften des ListView-Steuerelements
Die Anzeige der Adressen erfolgt in einem ListView-Steuerelement. Steuerelemente dieses Typs können ihr Aussehen ähnlich flexibel verändern wie die Dateiansicht im Windows Explorer. Für die Anzeige der Adressen ist die Anzeige aller Spalten (View.Details) ohne Bilder oder Sonstiges erforderlich. Außerdem muss ein Mausklick stets nur einen Datensatz markieren (FullRowSelect = True, MultiSelect = False).
Die Prozedur SetListViewProperties setzt alle erforderlichen Eigenschaften zur Anzeige des ListView-Steuerelements (s. Quellcode 10).
Kopfzeile
Das ListView-Steuerelement soll nur ausgewählte Spalten anzeigen. Bei der Definition des Steuerelements müssen Sie die Spalten einzeln per Add-Methode hinzufügen. Die Methode gibt Ihnen die Möglichkeit, für jede Spalte auch gleich eine Überschrift zu definieren. Die Methode AddHeader definiert alle Überschriften des ListView-Steuerelements (s. Quellcode 11).
Daten im ListView-Steuerelement anzeigen
Die ShowData-Prozedur übernimmt die Anzeige der Adressen im ListView-Steuerelement (s. Quellcode 12). Die Prozedur bietet den Komfort, dass sie sich am Anfang die Nummer der im ListView-Steuerelement markierten Zeile merkt.
Die GetAdressen-Methode des DataLayer-Objekts liest die Adressdaten aus der Access-Datenbank.
Private Sub ShowData()
Try
Dim iSelected As Integer
If lstvAdressen.Items.Count > 0 Then
iSelected = 0
If lstvAdressen.SelectedItems.Count > 0 _ Then
iSelected = lstvAdressen. _ SelectedItems.Item(0).Index
End If
End If
Dim tblAdressen As New DataTable
tblAdressen = m_DataLayer.GetAdressen()
Dim row As DataRow
Dim Item As ListViewItem
lstvAdressen.Items.Clear()
If tblAdressen.Rows.Count > 0 Then
lstvAdressen.BeginUpdate()
Item = New ListViewItem
For Each row In tblAdressen.Rows
Item = lstvAdressen.Items. _ Add(row.Item("Anrede").ToString())
With Item.SubItems
.Add(row.Item("Vorname").ToString())
.Add(row.Item("Nachname").ToString())
.Add(row.Item("Strasse").ToString())
.Add(row.Item("PLZ").ToString())
.Add(row.Item("Ort").ToString())
End With
Item.Tag = row
Next
lstvAdressen.EndUpdate()
Else
m_Modus = Modus.Null
End If
If lstvAdressen.Items.Count > 0 Then
iSelected = System.Math.Min(iSelected, _ lstvAdressen.Items.Count - 1)
lstvAdressen.Items(iSelected).Selected _ = True
End If
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Quellcode 12
Die Anzeige erfolgt in einer Schleife, die alle Zeilen des DataTable-Objekts durchläuft. Für jeden Datensatz wird ein Item-Objekt im ListView-Steuerelement hinzugefügt.
Die Struktur des Steuerelements ist insofern ungewöhnlich, als dass es keine Spaltenauflistung im eigentlichen Sinne gibt. Es ist vielmehr so, dass mit Ausnahme der ersten Spalte für jede im Header definierte Spalte pro Item ein SubItem hinzugefügt werden muss. Die mit AddHeader definierte Kopfzeile hat sechs Spalten. Pro Datensatz ist deshalb ein Item mit fünf SubItems erforderlich. Die SubItems werden dem Item-Objekt einfach per Add-Methode hinzugefügt.
|