Laufen wir in der IDE?

Unter .NET kann man prüfen, ob das hier wahr ist:

System.Diagnostics.Debugger.IsAttached
System.Diagnostics.Debugger.IsAttached

Falls ja, befinden wir uns in der IDE. Ansonsten sind wir ein Kompilat (nein, kein Kombinat, das war etwas anderes…)

Doppelten Eintrag in Datenbank löschen

Natürlich lohnt es nicht, einen Blogeintrag über das Löschen von Datensätzen in einer Datenbank zu schreiben. Es sei denn, der Dorftrottel hat die Tabelle entworfen… Dann kann es nämlich durchaus vorkommen ist es meistens so, dass in der Tabelle kein Index und keine Art von Schlüssel vorkommt. Natürlich wird bei der Dateneingabe auch nie geprüft, ob ein entsprechender Eintrag vielleicht schon vorhanden ist. Es kommt dann wie es kommen muss: Irgendwann fallen doppelte (in allen Feldwerten gleichlautende) Datensätze an. Und dann ist es nicht mehr weit, bis jemand schreit, dass ein Datensatz oder n Einträge gelöscht werden müssen.

Wie löscht man nun gleiche Einträge, wenn sich die Datensätze nicht unterscheiden? Mit SQL geht’s nicht, da man keine Einschränkung zur Auswahl eines Datensatzes findet. Mit dem Management-Studio geht’s auch nicht, es meckert, dass eventuell alle Datensätze betroffen sind. Also einfach alle Datensätze wegpölen und neu eingeben?

Mit SQL geht’s aber doch, wenigstens seit SQL Server 2005. Dort kann man in der DELETE Anweisung (wie auch in der UPDATE Anweisung) ein TOP ROW angeben. Um den ersten eines doppelten Eintrags zu löschen, reicht es

DELETE TOP (1) FROM tabelle WHERE feld = xyz
DELETE TOP (1) FROM tabelle WHERE feld = xyz

zu schreiben. Es wird dann tatsächlich der erste (bzw. beliebige) Eintrag eines doppelten (drei-, vier-, n-fachen)  Eintrags gelöscht.

Menüstruktur durchlaufen in VB.NET

Daran bin ich fast schon einmal verzweifelt. Ein Menü zu durchlaufen ist in meinen Augen schwieriger als man zunächst denkt.
“Ganz oben” gibt es den/das MenuStrip. Das ist die oberste Hierarchie (optisch kann man sich das MenuStrip als “das erste Menü unterhalb der Titelleiste” denken). Alles andere sind DropdownItems (bzw. ToolStripMenuItems), die am MenuStrip hängen. So viel zum theoretischen  Unterbau. Wer mehr darüber erfahren möchte, kann googlen.

Da eine Menüstruktur verschachtelt sein kann, müssen auch alle Unterknoten durchlaufen werden. Es bietet sich an, dafür eine Rekursion zu verwenden. (Das war übrigens eine der ganz wenigen Stellen in meinem Leben, an denen ich spontan gedacht habe: das eignet sich supergut für eine Rekursion.)

Einen Haken hat die Sache noch: bei Separatoren (horizontale Trennlinien im Menü) fällt der Cast des DropDownItems in ein ToolStripMenuItem auf die Nase.  Deswegen muss das vorher noch abgefragt werden.

(Ziel der Übung war es übrigens, den Tooltip jedes einzelnen Menüeintrags zu leeren. Das MenuStrip bringt eine eigene ToolTip-Verwaltung mit sich. Daher funktioniert es nicht, einfach das formulargebundene ToolTip-Control zu deaktivieren, da die Tooltips der Menüs nicht daran hängen.)

Private Sub LoescheToolTips()
  For i As Integer = 0 To MenuStrip1.Items.Count - 1
    Unterknoten(MenuStrip1.Items(i))
  Next
End Sub
Private Sub LoescheToolTips()
  For i As Integer = 0 To MenuStrip1.Items.Count - 1
    Unterknoten(MenuStrip1.Items(i))
  Next
End Sub
Private Sub Unterknoten(ByVal Tsmi As ToolStripMenuItem)
For j As Integer = 0 To Tsmi.DropDownItems.Count – 1
    Tsmi.DropDownItems(j).ToolTipText = "" ‘ Hier kann man den Menüpunkt verwursten.
      If Tsmi.DropDownItems(j).IsOnDropDown Then
        If Not (TypeOf Tsmi.DropDownItems(j) Is System.Windows.Forms.ToolStripSeparator) Then
          Unterknoten(DirectCast(Tsmi.DropDownItems(j), ToolStripMenuItem))
        End If
    End If
  Next
End Sub
Private Sub Unterknoten(ByVal Tsmi As ToolStripMenuItem)
For j As Integer = 0 To Tsmi.DropDownItems.Count – 1
    Tsmi.DropDownItems(j).ToolTipText = "" ‘ Hier kann man den Menüpunkt verwursten.
      If Tsmi.DropDownItems(j).IsOnDropDown Then
        If Not (TypeOf Tsmi.DropDownItems(j) Is System.Windows.Forms.ToolStripSeparator) Then
          Unterknoten(DirectCast(Tsmi.DropDownItems(j), ToolStripMenuItem))
        End If
    End If
  Next
End Sub

Listview unter VB6

Weil ich immer wieder gerne vergesse, wie es mit diesem Listview unter VB6 funktioniert…
Hier eine kleine Demo, die ein Listview aufbaut. Durch Klick auf einen Spaltenkopf wird nach der Spalte sortiert.
Das war schon alles.

' Im Projekt müssen die "Microsoft Windows Common Controls 6.0" hinzugefügt werden.
' Es muss Version 6 sein! Version 5 erkennt "MSComctlLib.ColumnHeader" nicht.

' Ein ListView1 muss der Form hinzugefügt werden.

Private Sub Form_Load()
Dim lvI As Long
Dim lvListitem As ListItem
 
ListView1.View = lvwReport
ListView1.HideColumnHeaders = False
ListView1.ColumnHeaders.Add , "E1", "Sp1"
ListView1.ColumnHeaders.Add , "E2", "Test"
ListView1.ColumnHeaders.Add , "E3", "Drei"
 
For lvI = 1 To 10
Set lvListitem = ListView1.ListItems.Add(, "E" & lvI, lvI)
lvListitem.SubItems(1) = CStr(Int(Rnd * 100))
lvListitem.SubItems(2) = "Test"
Next lvI
 
End Sub
' Im Projekt müssen die "Microsoft Windows Common Controls 6.0" hinzugefügt werden.
' Es muss Version 6 sein! Version 5 erkennt "MSComctlLib.ColumnHeader" nicht.

' Ein ListView1 muss der Form hinzugefügt werden.

Private Sub Form_Load()
Dim lvI As Long
Dim lvListitem As ListItem

ListView1.View = lvwReport
ListView1.HideColumnHeaders = False
ListView1.ColumnHeaders.Add , "E1", "Sp1"
ListView1.ColumnHeaders.Add , "E2", "Test"
ListView1.ColumnHeaders.Add , "E3", "Drei"

For lvI = 1 To 10
Set lvListitem = ListView1.ListItems.Add(, "E" & lvI, lvI)
lvListitem.SubItems(1) = CStr(Int(Rnd * 100))
lvListitem.SubItems(2) = "Test"
Next lvI

End Sub
Private Sub ListView1_ColumnClick(ByVal ColumnHeader As MSComctlLib.ColumnHeader)
 
ListView1.SortKey = ColumnHeader.SubItemIndex
ListView1.Sorted = True
 
End Sub
Private Sub ListView1_ColumnClick(ByVal ColumnHeader As MSComctlLib.ColumnHeader)

ListView1.SortKey = ColumnHeader.SubItemIndex
ListView1.Sorted = True

End Sub

Todos und Do Nots

Die wichtigsten Tue und TueNicht für Programmierer in Kurzform:

  • Programmiere nach Standards

Akzeptiere, dass geschulte Leute, die mal wichtige Algorithmen entwickelt haben, Plan davon hatten. Erfinde den Quicksort nicht neu. Benutze den Standard.

  • Kommentiere, aber nicht auf Teufel komm raus

Kommentare sind wichtig. Aber kommentiere keine Funktion, die “ErmittleKundenname” heißt mit  dem Kommentar “Ermittelt den Kundennamen”. Beschreibe, warum du den Kundennamen genau so ermittelst, wie du  es in dieser Routine tust.

  • Benutze eine Sourcecodeverwaltung

Auch bei kleinen Programmen. Du kannst so immer wieder zu der Stelle zurückspringen, bevor du dich furchtbar verfranst hast. Du hast Überblick und Ordnung. Disziplin kann auch gut sein.

  • Baue ein Programm so, wie du es auch vorfinden wolltest, wenn es ein anderer programmiert hätte

Schwierig, denn jeder Programmierer hat andere Vorstellungen vom programmieren. Deswegen: halte dich an Standards. Dann klappt’s auch mit dem Kollegen.

  • Programmiere keine überflüssigen Dinge.

Jedes Goodie, was du einbaust, damit der Kunde sieht, wie toll du bist, kommt irgendwann zu dir zurück. Entweder als Ding, was du ständig warten musst oder als überflüssigen Tand, den du wieder ausbauen musst. Wenn du unbedingt etwas “cooles” einbauen möchtest, sprich es mit dem Kunden vorher ab!

  • Ach ja, denke immer an den Kunden.

Er ist der Geldgeber. Er zahlt deine Miete, dein Essen, deinen Lebensstandard. Der Kunde muss letzten Endes glücklich sein. Mache alles, damit er glücklich ist. :)