VB.NET Kalender erstellen – Teil 1

VB.NET Kalender erstellen – Teil 1
VB.NET Kalender erstellen – Teil 1

VB.NET Kalender erstellen – Teil 1

Lerne in dem ersten Beitrag meiner zweiteiligen Reihe, wie Du deinen eigenen VB.NET Kalender erstellen kannst, sogar mit Terminen!

Ich habe das Thema Terminkalender, bzw. einen eigenen Kalender in VB.NET zu erstellen schonmal in einem ehemaligen Beitrag über den BackgroundWorker angesprochen.

Statt einem BackgroundWorker, oder einem Timer, werden wir in diesem Beispiel die moderne Async/Await-Variante verwenden.

Zweiter Teil!?

Du bist auf der Suche nach dem zweiten Teil – hier wirst Du fündig!

Vorwort

Ich würde Dich bitten, dass Du mich auf dir auffallende Fehler durch ein Kommentar hinweist.

Da es sich hierbei natürlich um einen etwas größeren Beitrag handelt, kann es leicht vorkommen, dass ich mal was vergesse.

Ich habe mir bei der Qualität des Codes viel Mühe gegeben, allerdings wird es immer vorkommen, dass jemand etwas anders macht, oder meint besser zu machen.

Es steht Dir daher selbstverständlich frei, den Code nach deinen Belieben anzupassen, bzw. zu modifizieren.

Bei meiner Planung und Durchführung des Beitrages habe ich mir natürlich auch irgendwo Gedanken über meine Zeit gemacht, daher musste ich hier und da Abstriche machen.

Ich denke aber, dass dieser Beitrag sehr gelungen ist und vielen Anfängern und auch Fortgeschrittenen VB.NET Entwicklern bei der Erstellung eines eigenen VB.NET Kalenders helfen kann.

Fragen – VB.NET Kalender erstellen

  • Wie möchten wir den Kalender allgemein darstellen?
  • Möchten wir verschiedene Ansichten wie Monats-, Wochen- und Tagesansicht?
  • Auf welche Art, sollen die Termine dargestellt werden?
  • Soll der Kalender auch eine Art Erinnerungsfunktion haben?
  • Können Termine gespeichert werden und wenn ja wie?
  • Sollen die Bestandteile responsiv sein?
  • Wie komplex soll das Ganze werden?
  • und und und..

Eigene Termine

Da jeder vermutlich die Termine mit anderen Daten versehen wird, habe ich hier bewusst ein Interface erstellt, Welches nur die Basis-Funktionalität eines Termins widerspiegelt.

Jeder kann somit seine eigene Termin (Appointment)-Klasse erstellen und mit weiteren Daten befüllen.

Dazu kann man entweder von der AppointmentKlasse erben, direkt darin weiter schreiben, oder eben seine eigene Klasse erstellen, die dann das IAppointmentInterface implementiert.

Aus den meisten Kalendern kennt man es, dass links außen so ein Kreis für z. B. die Priorität dargestellt wird.

Ebenso haben alle Termine ein Startdatum inkl. Uhrzeit und ein Enddatum plus Uhrzeit.

IAppointment

Public Interface IAppointment

    Property Circle As Color

    Property Start As Date

    Property [End] As Date

    Property Subject As String

End Interface

Appointment

Public Class Appointment
    Implements IAppointment

    Public Property Circle As Color Implements IAppointment.Circle

    Public Property Start As Date Implements IAppointment.Start

    Public Property [End] As Date Implements IAppointment.End

    Public Property Subject As String Implements IAppointment.Subject

    Sub New()
        Circle = Color.Red
        Start = Date.Now
        [End] = Date.Now.AddHours(1)
        Subject = "Neuer Termin"
    End Sub

End Class

Erweiterungsmethoden – VB.NET Kalender erstellen

Da wir in dem Beispiel ganz häufig auf irgendwelche DatumsFunktionen zurückgreifen werden müssen, die es vom .NET Framework (jedenfalls mir nicht bekannt) nicht gibt, bauen wir uns unsere eigenen Helfer.

Imports System.Globalization
Imports System.Runtime.CompilerServices

Public Module modDateExtensions

    Public Enum Days
        Monday = 1
        Tuesday = 2
        Wednesday = 3
        Thursday = 4
        Friday = 5
        Saturday = 6
        Sunday = 7
    End Enum

    <Extension>
    Public Function FirstDayOfMonth(dt As Date) As Date
        Return New Date(dt.Year, dt.Month, 1, dt.Hour, dt.Month, dt.Second, dt.Millisecond)
    End Function

    <Extension>
    Public Function LastDayOfMonth(dt As Date) As Date
        Dim nextMonth As Integer
        If dt.Month = 12 Then
            nextMonth = 1
        Else
            nextMonth = dt.Month + 1
        End If
        Dim firstOfNextMonth = New Date(dt.Year, nextMonth, 1, dt.Hour, dt.Month, dt.Second, dt.Millisecond)
        Return firstOfNextMonth.AddDays(-1)
    End Function

    <Extension>
    Public Function CalendarWeek(dt As Date) As Integer
        Dim day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(dt)

        If day >= DayOfWeek.Monday AndAlso day <= DayOfWeek.Wednesday Then
            dt = dt.AddDays(3)
        End If

        Return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(dt, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday)
    End Function

    <Extension>
    Public Function GetPreviousDay(dt As Date, day As Days) As Date
        Dim targetDate = dt
        Do
            targetDate = targetDate.AddDays(-1)
        Loop While Weekday(targetDate, FirstDayOfWeek.Monday) > day
        Return targetDate
    End Function

    <Extension>
    Public Function GetNextDay(dt As Date, day As Days) As Date
        Dim targetDate = dt
        Do
            targetDate = targetDate.AddDays(1)
        Loop While Weekday(targetDate, FirstDayOfWeek.Monday) < day
        Return targetDate
    End Function

    <Extension>
    Public Function Range(from As Date, [to] As Date, Optional inclusive As Boolean = True) As List(Of Date)
        Dim days = New List(Of Date)
        If inclusive Then
            Dim CurrentDate = from
            While CurrentDate <= [to]
                days.Add(CurrentDate)
                CurrentDate = CurrentDate.AddDays(1)
            End While
        Else
            Dim CurrentDate = from.AddDays(1)
            While CurrentDate < [to]
                days.Add(CurrentDate)
                CurrentDate = CurrentDate.AddDays(1)
            End While
        End If
        Return days
    End Function

End Module

Wenn Dir bessere Varianten einfallen, um die genannten Methoden zu verbessern, bist Du natürlich gerne eingeladen, den Code zu verbessern.

Mir reichen Diese Implementierungen allerdings so, da Sie mir so in den Kopf gekommen sind und ich sie einfach so runtergeschrieben habe.

FirstDayOfMonth(dt)

Diese Funktion dient dazu, den ersten Tag eines Monats zu bekommen.

LastDayOfMonth(dt)

Mit dieser Funktion kommen wir an den letzten Tag eines Monats.

CalendarWeek(dt)

Holt die Nummer der Kalenderwoche anhand eines gegebenen Datums.

GetPreviousDay(dt, day)

Gibt den letzten angegebenen Tag wieder, der anhand des Day-Parameters übergeben wurde.

GetNextDay(dt, day)

Errechnet den nächsten angegebenen Tag wieder, der durch den Day-Parameter übergeben wurde.

Range(from, to, inclusive)

Gibt eine Liste von Tagen die zwischen den beiden Daten liegen wieder (exklusiv, oder inklusiv).

VB.NET Kalender erstellen

Tipp!

Da wir in diesem Beispiel etwas zeichnungsintensivere Controls haben, solltest Du die „DoubleBuffered„-Eigenschaft der Form und auch ggf. der Sub-Elemente auf True stellen.

Los geht’s

Dann legen wir mit der Erstellung unseres Kalenders mal los, der erste Schritt wäre, ein Steuerelement zu erstellen.

Calendar-Klasse – VB.NET Kalender erstellen

Mache dazu einfach einen Rechtsklick rechts außen im ProjektmappenExplorer auf dein Projekt und dann Hinzufügen->Benutzersteuerelement (Windows Forms).

Alternativ kannst Du oben im Menü auf Projekt->Benutzersteuerelement hinzufügen (Windows Forms) klicken.

Da es sich bei unserem Vorhaben um einen Kalender handelt, nennen wir das Steuerelement – wer hätte es gedacht – Calendar (natürlich englisch, in der Welt der Programmierung).

Public Class Calendar

    Private _date As Date = Date.Now

    Public Property [Date] As Date
        Get
            Return _date
        End Get
        Set(value As Date)
            _date = value
            RefreshData()
        End Set
    End Property

    Private Property RowPanels As List(Of TableLayoutPanel)

    Public Property RowHeaders As List(Of RowHeader)

    Public Property Days As List(Of Day)

    Sub New()
        InitializeComponent()
        Dock = DockStyle.Fill
        RowPanels = New List(Of TableLayoutPanel) From {
            tlpRow1,
            tlpRow2,
            tlpRow3,
            tlpRow4,
            tlpRow5
        }
        RowHeaders = New List(Of RowHeader)
        Days = New List(Of Day)
        BuildUp()
    End Sub

    Private Sub BuildUp()
        GenerateHeaderRow()
        GenerateRows()
    End Sub

    Private Sub GenerateHeaderRow()
        GeneratePlaceholderBox()
        GenerateDayLabels()
    End Sub

    Private Sub GeneratePlaceholderBox()
        Dim placeholder = New PictureBox()
        With placeholder
            .Dock = DockStyle.Fill
            .BackColor = Color.White
            .Margin = New Padding(0)
        End With
        tlpHeader.Controls.Add(placeholder)
    End Sub

    Private Sub GenerateDayLabels()
        Dim dayNames = GetDayNames()
        For Each dayName In dayNames
            Dim lbl = New Label()
            With lbl
                .Text = dayName.Substring(0, 2).ToUpper()
                .Dock = DockStyle.Fill
                .AutoSize = False
                .TextAlign = ContentAlignment.MiddleCenter
                .ForeColor = Color.Black
                .Font = New Font(New FontFamily("Segoe UI"), 12, FontStyle.Regular)
            End With
            tlpHeader.Controls.Add(lbl)
        Next
    End Sub

    Private Function GetDayNames() As List(Of String)
        Dim anyMonday = Date.Parse("05.07.2021")
        Dim nextSunday = anyMonday.AddDays(6)
        Dim week = anyMonday.Range(nextSunday)
        Dim dayNames = New List(Of String)
        For Each day In week
            Dim dayName = day.ToString("ddd")
            dayNames.Add(dayName)
        Next
        Return dayNames
    End Function

    Private Sub GenerateRows()
        Dim days = GetDateRange()
        Dim index = 0
        Dim number = 1
        For i = 1 To 5
            Dim rowIndex = i - 1
            Dim startOfWeek = days(index)
            ' Dim endOfWeek = days(index).AddDays(6)
            GenerateRowHeader(rowIndex, startOfWeek)
            For j = 1 To 7
                Dim colIndex = j - 1
                GenerateDay(days(index), rowIndex, colIndex, number)
                index += 1
                number += 1
            Next
        Next
    End Sub

    Private Sub GenerateRowHeader(rowIndex As Integer, startOfWeek As Date)
        Dim rowHeaderHasTopBorder = rowIndex > 0
        Dim rowHeader = New RowHeader(startOfWeek.CalendarWeek(), rowHeaderHasTopBorder)
        RowPanels(rowIndex).Controls.Add(rowHeader)
        RowHeaders.Add(rowHeader)
    End Sub

    Private Sub GenerateDay(dt As Date, rowIndex As Integer, colIndex As Integer, number As Integer)
        Dim day = New Day(dt)
        With day
            .HasTopBorder = rowIndex > 0
            .HasRightBorder = colIndex < 6
            .HasBottomBorder = rowIndex < 4
            .HasLeftBorder = number Mod 7 <> 0
        End With
        RowPanels(rowIndex).Controls.Add(day)
        Days.Add(day)
    End Sub

    Private Sub RefreshData()
        ClearEntries()
        RefreshDateLabel()
        RefreshRowHeaders()
        RefreshDays()
    End Sub

    Public Sub ClearEntries()
        For Each day In Days
            day.ClearEntries()
        Next
    End Sub

    Private Sub RefreshDateLabel()
        lblDate.Text = [Date].ToString("MMMM yyyy")
    End Sub

    Private Sub RefreshRowHeaders()
        Dim dates = GetDateRange()
        For i = 0 To 4
            RowHeaders(i).CalendarWeek = dates(i * 7).CalendarWeek()
        Next
    End Sub

    Private Sub RefreshDays()
        Dim dates = GetDateRange()
        For i = 0 To dates.Count - 1
            Dim day = Days(i)
            Dim dt = dates(i)
            day.Date = dt
        Next
    End Sub

    Public Function GetDateRange() As List(Of Date)
        Dim lastMonday As Date
        If Weekday([Date], FirstDayOfWeek.Monday) = WeekDays.Monday Then
            lastMonday = [Date]
        Else
            lastMonday = [Date].GetPreviousDay(WeekDays.Monday)
        End If
        Dim range = lastMonday.Range(lastMonday.AddDays(34))
        Return range
    End Function

    Public Sub GoToToday()
        [Date] = Date.Now
    End Sub

    Public Sub GoForward()
        [Date] = [Date].LastDayOfMonth().AddDays(1)
    End Sub

    Public Sub GoBack()
        [Date] = [Date].FirstDayOfMonth().AddDays(-1).FirstDayOfMonth()
    End Sub

    Private Sub btnBack_Click(sender As Object, e As EventArgs) Handles btnBack.Click
        GoBack()
    End Sub

    Private Sub btnForward_Click(sender As Object, e As EventArgs) Handles btnForward.Click
        GoForward()
    End Sub

    Private Sub btnToday_Click(sender As Object, e As EventArgs) Handles btnToday.Click
        GoToToday()
    End Sub

    Public Event EntryClicked As EventHandler

    Public Event EntryDoubleClicked As EventHandler

End Class

Eigenschaften

Date

Die Date Eigenschaft speichert das aktuelle Datum des Kalenders zwischen.

Obwohl der Kalender ja praktisch in unserem Fall nur Monat + Jahr anzeigt und damit arbeitet, lässt Er sich so bei Bedarf erweitern, ohne großartig was am Flow ändern zu müssen.

Im Setter der Date-Eigenschaft triggern wir automatisch das „Refreshen“, also Aktualisieren der Daten.

RowPanels

Diese Eigenschaft dient mehr oder weniger als Zwischenspeicher, um einfacher auf die Rows zugreifen zu können.

RowHeaders

Ebenfalls eine Art Cache/Zwischenspeicher, um einfacheren Zugriff zu erhalten.

Days

Auch hier handelt es sich um einen Zwischenspeicher.

Konstruktor

Im Konstruktor der CalendarKlasse lege ich die Dock-Eigenschaft auf Fill fest, damit der Kalender standardmäßig seinen Container füllt.

Dann Befülle ich den „RowCache„, da die Rows an sich ja schon zu Designer-Zeit existieren und instanziiere anschließend die weiteren CacheListen, die gleich noch befüllt werden.

Zum Schluss wird einmalig das Grundgerüst des Kalenders erstellt, damit wir das nicht bei jedem Datums-Wechsel neu durchlaufen müssen.

Es wird später aus PerformanceGründen nur das aktualisiert, was auch aktualisiert werden muss, bzw. so wenig wie möglich.

Steuerelemente

splcMain

Das erste und zuerst wichtigste Solo-Steuerelement was das Calendar-Control bekommen sollte ist vermutlich der SplitContainer, den wir splcMain nennen werden.

Diesen SplitContainer verwenden wird, um den Kalender in 2 Bereiche zu unterteilen: Den oberen Bereich, wo einzelne Navigations-Elemente hineinkommen.

Und als nächstes den zweiten Bereich, wo die Navigation und die einzelnen Tage responsiv dargestellt werden.

Dazu wird eine Kombination aus verschiedenen Panels verwendet.

btnToday

Mit diesem Button navigieren wir an den heutigen Tag.

btnBack

Dieser Button lässt den Kalender auf den vorherigen Monat springen.

btnForward

Der Button btnForward lässt den Kalender auf die nächste Seite, sprich zu dem nächsten Monat „blättern“.

lblDate

Dieses Label gibt uns eine Information darüber, auf welcher Seite“ wir uns praktisch befinden, indem es den Namen des Monat und eine Jahreszahl anzeigt.

pbBottomBorder

Um einen kleinen Rand anzuzeigen, habe ich dafür eine PictureBox mit BackColor missbraucht.

Damit die späteren Beispiele allerdings „sauberer“ bleiben, bin ich dort im Paint-Event manuell ans Zeichnen gegangen..

Entry-Klasse – VB.NET Kalender erstellen

Die Entry-Klasse steht für einen jeweiligen Eintrag im Kalender-Tag.

Public Class Entry

    Public Property Appointment As IAppointment

    Sub New(appointment As IAppointment)
        InitializeComponent()
        Me.Appointment = appointment
        lblTime.Text = appointment.Start.ToString("HH:mm")
        lblSubject.Text = appointment.Subject
    End Sub

    Private Sub tlpMain_CellPaint(sender As Object, e As TableLayoutCellPaintEventArgs) Handles tlpMain.CellPaint
        If e.Column = 0 Then
            Using brush = New SolidBrush(Appointment.Circle)
                e.Graphics.FillEllipse(brush, e.CellBounds)
            End Using
        End If
    End Sub

    Private Sub Entry_Clicked(sender As Object, e As EventArgs) Handles lblSubject.Click, lblTime.Click, tlpMain.Click, Me.Click
        RaiseEvent Clicked(sender, e)
    End Sub

    Private Sub Entry_DoubleClicked(sender As Object, e As EventArgs) Handles lblSubject.DoubleClick, lblTime.DoubleClick, tlpMain.DoubleClick, Me.DoubleClick
        RaiseEvent DoubleClicked(sender, e)
    End Sub

    Public Event Clicked As EventHandler

    Public Event DoubleClicked As EventHandler

End Class

Eigenschaften

Appointment

Der Termin der hinter dem letztendlichen Eintrag steht – Kann irgendeine Implementierung des IAppointment-Interface sein!

Konstruktor

new(appointment)

Der Konstruktor erwartet einen Termin als Parameter (Achtung, irgendeine Implementierung des IAppointment Interfaces!)

Nachdem der Termin gesetzt ist, werden die Texte der Labels angepasst.

Methoden

tlpMain_CellPaint

Hier zeichnen wir in der ersten Spalte des TableLayoutPanels einen Kreis in der für den Termin angegebenen Farbe.

Entries klickbar machen

Um die Entries richtig klickbar zu machen, müssen wir auf alle GUI-Elemente reagieren, also wenn Diese geklickt werden.

Dafür habe ich zwei Ereignishandler erstellt, die die Klick- und Doppelklick-Ereignisse der Elemente auf dem Entry abfangen und als eigenes Event weiterleiten„.

Vorschau auf die Tage

Auch wenn der rote Kreis hier nicht so ganz meinen Vorstellungen entspricht, ich lasse es erstmal so.

Du bist herzlich eingeladen, den Kreis anhand deiner Wünsche anzupassen!

VB.NET Kalender erstellen Tag Kachel
VB.NET Kalender erstellen Tag Kachel

RowHeader-Klasse – VB.NET Kalender erstellen

Im folgenden Schritt werden wir die RowHeader-Klasse, bzw. das RowHeader-Steuerelement erstellen.

Es dient als Spacer für die Reihen links außen und stellt mit einem passenden Hintergrund die Kalenderwoche dar.

Public Class RowHeader

    Private _calendarWeek As Integer

    Public Property CalendarWeek As Integer
        Get
            Return _calendarWeek
        End Get
        Set(value As Integer)
            _calendarWeek = value
            lblCalendarWeek.Text = value.ToString()
        End Set
    End Property

    Public Property HasTopBorder As Boolean

    Sub New(calendarWeek As Integer, Optional hasTopBorder As Boolean = True)
        InitializeComponent()
        Dock = DockStyle.Fill
        Me.CalendarWeek = calendarWeek
        Me.HasTopBorder = hasTopBorder
    End Sub

    Private Sub RowHeader_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        If HasTopBorder Then DrawTopBorder(e.Graphics)
    End Sub

    Private Sub DrawTopBorder(graphics As Graphics)
        graphics.DrawLine(Pens.Black, New Point(0, 0), New Point(Width - 1, 0))
    End Sub

End Class

Eigenschaften

CalendarWeek

Die CalendarWeek-Eigenschaft speichert die Kalenderwoche als Zahl und updatet im Setter automatisch den zugehörigen LabelText.

Konstruktor

new(calendarWeek, hasTopBorder)

Im Konstruktor braucht ein RowHeader die Kalenderwoche als Zahl und die Info, ob er den Top-Rand zeichnen soll, oder nicht.

Methoden

RowHeader_Paint

Wir verwenden einen Paint-Ereignishandler, um den TopRand falls aktiviert zu zeichnen.

DrawTopBorder

Das Zeichnen des Top-Randes selbst.

Day darstellen

Jetzt erstellen wir die Kacheln um ein jeweiligen Tag darzustellen.

Auch dafür nehmen wir ein neues Benutzersteuerelement (Windows Forms) und fangen an zu designen.

Public Class Day

    Private _date As Date

    Public Property [Date] As Date
        Get
            Return _date
        End Get
        Set(value As Date)
            _date = value
            lblDayNumber.Text = value.Day
        End Set
    End Property

    Public Property Entries As List(Of Entry)

    Public Property HasTopBorder As Boolean

    Public Property HasRightBorder As Boolean

    Public Property HasBottomBorder As Boolean

    Public Property HasLeftBorder As Boolean

    Private Property BorderPen As Pen

    Sub New([date] As Date)
        InitializeComponent()
        Dock = DockStyle.Fill
        BorderPen = New Pen(Color.LightGray)
        Me.[Date] = [date]
        Me.Entries = New List(Of Entry)
    End Sub

    Public Sub ClearEntries()
        For Each entry In tlpInner.Controls.OfType(Of Entry)
            RemoveHandler entry.Clicked, AddressOf AnEntryClicked
            RemoveHandler entry.DoubleClicked, AddressOf AnEntryDoubleClicked
            entry.Appointment = Nothing
        Next
        tlpInner.Controls.Clear()
    End Sub

    Public Sub AddEntry(entry As Entry)
        Entries.Add(entry)
        AddHandler entry.Clicked, AddressOf AnEntryClicked
        AddHandler entry.DoubleClicked, AddressOf AnEntryDoubleClicked
    End Sub

    Public Sub RemoveEntry(entry As Entry)
        RemoveHandler entry.Clicked, AddressOf AnEntryClicked
        RemoveHandler entry.DoubleClicked, AddressOf AnEntryDoubleClicked
        Entries.Remove(entry)
    End Sub

    Private Sub Day_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        DrawBorders(e.Graphics)
    End Sub

    Private Sub DrawBorders(graphics As Graphics)
        If HasTopBorder Then DrawTopBorder(graphics)
        If HasRightBorder Then DrawRightBorder(graphics)
        If HasBottomBorder Then DrawBottomBorder(graphics)
        If HasLeftBorder Then DrawLeftBorder(graphics)
    End Sub

    Private Sub DrawTopBorder(graphics As Graphics)
        graphics.DrawLine(BorderPen, New Point(0, 0), New Point(Width, 0))
    End Sub

    Private Sub DrawRightBorder(graphics As Graphics)
        graphics.DrawLine(BorderPen, New Point(Width - 1, 0), New Point(Width - 1, Height))
    End Sub

    Private Sub DrawBottomBorder(graphics As Graphics)
        graphics.DrawLine(BorderPen, New Point(0, Height - 1), New Point(Width, Height - 1))
    End Sub

    Private Sub DrawLeftBorder(graphics As Graphics)
        graphics.DrawLine(BorderPen, New Point(0, 0), New Point(0, Height))
    End Sub

    Private Sub AnEntryClicked(sender As Object, e As EventArgs)
        OnEntryClicked(EventArgs.Empty)
    End Sub

    Protected Sub OnEntryClicked(e As EventArgs)
        RaiseEvent EntryClicked(Me, e)
    End Sub

    Private Sub AnEntryDoubleClicked(sender As Object, e As EventArgs)
        OnEntryDoubleClicked(EventArgs.Empty)
    End Sub

    Protected Sub OnEntryDoubleClicked(e As EventArgs)
        RaiseEvent EntryDoubleClicked(Me, e)
    End Sub

    Private Sub DayClicked(sender As Object, e As EventArgs) Handles lblDayNumber.Click, tlpMain.Click, tlpInner.Click
        OnClicked(EventArgs.Empty)
    End Sub

    Protected Sub OnClicked(e As EventArgs)
        RaiseEvent Clicked(Me, e)
    End Sub

    Private Sub DayDoubleClicked(sender As Object, e As EventArgs) Handles lblDayNumber.DoubleClick, tlpMain.DoubleClick, tlpInner.DoubleClick
        OnDoubleClicked(EventArgs.Empty)
    End Sub

    Protected Sub OnDoubleClicked(e As EventArgs)
        RaiseEvent DoubleClicked(Me, e)
    End Sub

    Public Event EntryClicked As EventHandler

    Public Event EntryDoubleClicked As EventHandler

    Public Event Clicked As EventHandler

    Public Event DoubleClicked As EventHandler

End Class

Ein jeweiliger Tag bekommt verschiedene Eigenschaften, die wir brauchen werden.

Eigenschaften

Date

Eine DateEigenschaft mit selbst implementierten Getter und Setter, damit wir beim setzen des Datums, den Text des Labels anpassen können.

Entries

Damit wir eine einfache und sinnvolle Möglichkeit haben, auf die einzelnen Einträge zugreifen zu können, statt via „tlpInner.Controls“ und ähnlichen Frickeleien.

Achtung: Mit Entries sollte nur via vorgesehenen Methoden gearbeitet werden (AddEntry, ClearEntries und RemoveEntry), sonst funktionieren die Handler nicht korrekt etc.

Border-Eigenschaften

Dann haben wir noch einzelne BorderEigenschaften, Welche man auch mit Flags als Zahlen, etc. lösen könnte, aber ich denke das Beispiel ist schon für viele Anfänger kompliziert genug!

BorderPen

Der Pen, also die Farbe, mit dem der Rand gemalt wird (Standard: LightGray).

Methoden

ClearEntries

Diese Methode ist ein Helper um alle Entries zu entfernen, dabei iteriert Sie alle Entries und säubert die Termin-Referenz und entfernt die Handler.

Zum Schluss werden alle Entries aus dem „Cache“ und aus der ControlsAuflistung des tlpInner gelöscht.

AddEntry(entry)

Diese Methode dient dazu, einen Eintrag mit passendem Handler und Zwischenspeicher in der Entries Auflistung hinzuzufügen.

Dabei beachtet Sie die Reihenfolge, sprich die Uhrzeit des Entries.

RemoveEntry(entry)

Entfernt den angegeben Entry aus der Controls-Auflistung und dem „Cache„.

Säubert ebenfalls die Handler und die Termin-Referenz.

DrawBorders & Co.

Wie der Name schon sagt, ist diese Methode und dessen SubMethoden dafür zuständig, die Ränder bei Bedarf zu zeichnen.

Click-Handler

Ansonsten gibt es noch nach .NET-Manier einige Handler, um das Arbeiten mit dem „Day“ zu vereinfachen, bzw. intuitiver zu gestalten.

Weiter zu Teil 2 – VB.NET Kalender erstellen

Wenn Du den zweiten Teil des Beitrages suchst, kannst Du Diesen hier finden!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert