Hier ein paar Codeschnipsel aus dem VB.NET bereich.

[vb.net] Grafische Progressbar in Datagridview-Zelle

Hallo zusammen.

Ich bin ein großer Freund des Datagridviews. Man kann Daten sehr einfach, übersichtlich und schön in einer Tabellenform darstellen. Doch manchmal möchte man dort auch gern eine Progressbar im Datagridview anzeigen lassen. Zum Beispiel wenn man sich einen Downloader bastelt und den aktuellen Stand des Downloads grafisch darstellen möchte. Oder auch wenn man statisch einen Prozentsatz grafisch darstellen möchte.

Leider gibt es standartmäßig keine Möglichkeit eine Progressbar in ein Datagridview einzubinden und das Element selbst unterstützt es auch nicht.

Nun führen bekanntlich viele Wege nach Rom. Manche sind lang und mühsam und manche sind recht simpel.
Ich habe auf meiner Suche Seitenlange Quelltexte gefunden, fertige DLL’s und schlussendlich eine sehr simple, aber effektive Möglichkeit. Die meine eigenen Überlegungen aufgegriffen hat. Nämlich die Progressbar einfach mit einem Bild zu imitieren. Das heißt es wird einfach ein Bild erstellt, welches dann in der entsprechenden Zelle eingebunden wird.
Dazu muss ich auch gleich sagen das diese Methode sehr Prozessorlastig werden kann, wenn viele “Progressbars” im Datagrid existieren und diese oft geupdated werden. Wie viel mehr das im Vergleich zu den anderen Methoden ist, kann ich jedoch nicht sagen. Vielleicht macht es gar keinen großen Unterschied. Also entscheide selbst ob es für dein Programm geeignet ist.

Hier nun erst einmal der Code.

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim col As New ProgressColumn
        DataGridView1.Columns.Add(col)
        DataGridView1.AllowUserToAddRows = False
        DataGridView1.RowCount = 5
        Dim x As Integer = 1
        For Each row As DataGridViewRow In DataGridView1.Rows
            row.Cells(0).Value = x * 20
            x += 1
        Next
    End Sub
End Class

Public Class ProgressColumn
    Inherits DataGridViewColumn
    Public Sub New()
        MyBase.New(New ProgressCell())
    End Sub

    Public Overrides Property CellTemplate() As DataGridViewCell
        Get
            Return MyBase.CellTemplate
        End Get
        Set(ByVal Value As DataGridViewCell)
            ' Ensure that the cell used for the template is a ProgressCell.
            If Value IsNot Nothing And Not TypeOf (Value) Is ProgressCell Then
                Throw New InvalidCastException("Must be a ProgressCell")
            End If
            MyBase.CellTemplate = Value
        End Set
    End Property
End Class

Public Class ProgressCell
    Inherits DataGridViewImageCell
    Protected Overrides Function GetFormattedValue(ByVal value As Object, ByVal rowIndex As Integer, ByRef cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal valueTypeConverter As System.ComponentModel.TypeConverter, ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter, ByVal context As System.Windows.Forms.DataGridViewDataErrorContexts) As Object
        ' Create bitmap.
        Dim bmp As Bitmap = New Bitmap(Me.Size.Width, Me.Size.Height)

        Using g As Graphics = Graphics.FromImage(bmp)

            ' Percentage.
            Dim percentage As Double = 0
            Double.TryParse(Me.Value.ToString(), percentage)
            Dim text As String = percentage.ToString() + " %"

            ' Get width and height of text.
            Dim f As Font = New Font("Verdana", 10, FontStyle.Regular)
            Dim w As Integer = CType(g.MeasureString(text, f).Width, Integer)
            Dim h As Integer = CType(g.MeasureString(text, f).Height, Integer)

            ' Draw pile.
            g.DrawRectangle(Pens.Black, 2, 2, Me.Size.Width - 6, Me.Size.Height - 6)
            g.FillRectangle(Brushes.Blue, 3, 3, CInt((Me.Size.Width - 6) * percentage / 100), CInt(Me.Size.Height - 7))

            Dim rect As RectangleF = New RectangleF(0, 0, bmp.Width, bmp.Height)
            Dim sf As StringFormat = New StringFormat()
            sf.Alignment = StringAlignment.Center
            g.DrawString(text, f, Brushes.Red, rect, sf)
        End Using

        Return bmp
    End Function


End Class

Was passiert hier nun?

Im Form_Load werden erst einmal die Datagridview-Spalten definiert und gefüllt. Dabei fällt auf das eine Zelle mit einem “ProgressColumn” definiert wird. Das ist unsere Spezielle Progressbar-Zelle. Diese kann durch die folgende Klasse “ProgressColumn” definiert werden.
Im Beispiel besteht unser Datagridview auch nur aus der einen Zelle (siehe auch Bild oben).

Dann wird das Datagridview-Element noch mit ein paar Testdaten gefüttert.

Die Klasse “ProgressColumn” lässt uns, wie gerade schon gesagt, eine spezielle Zelle definieren. Nämlich die für die Progressbar. Es ist ein Handler der erst definiert werden muss, bevor er genutzt werden kann. Verändert sich der Wert der Zelle so wird dieser Handler aufgerufen und er verarbeitet die Änderung. Um genau zu sein ruft er dann die Klasse ProgressCell auf, die wiederum das Bild erstellt.

Alle Änderungen die das Aussehen der Progressbar-Zelle betreffen, werden in der Klasse “ProgressCell” vorgenommen. Wir Hintergrundfarbe, Vordergrundfarbe, Textformatierung, usw.

Und das war es auch schon. Einfaches Prinzip, einfacher Code.

Ich hoffe das Hilft euch auch weiter… und mir beim nächsten mal auch wieder :)

Viele Grüße
Gordon

[VB.NET] RegEx Sonderzeichen maskieren

Hallo,

heute mal wieder eine kleine Notiz für mich – und alle die es auch ab und zu brauchen :)

RegEx (Regular Expressions) sagt sicher vielen etwas, die Programmieren. Nun kommt es aber auch mal vor das in der RegEx-Anweisung Zeichen vorkommen die eigentlich als Steuerzeichen reserviert sind. Wie zum Beispiel:

$ ^ { [ ( | ) * + ?

Sieht unsere Anweisung jetzt so aus

pattern = "<a href="(.*?)<strong><strong>?</strong></strong>.*?">.*?</a>"

haben wir schon ein Problem. Den das zweite Fragezeichen ist kein Sonderzeichen, sondern soll wirklich ein Fragezeichen im String sein. RegEx würde es jetzt aber als Teil einer Anweisung interpretieren.
Wie teilen wir jetzt VB.NET mit das es sich beim 2. Fragezeichen um einen ganz normalen Charakter handelt?

Ganz einfach. Wir maskieren es mit einem Backslash ‘/’. So sieht unser korrekter Pattern wie folgt aus:

pattern = "<a href="(.*?)<strong><strong>/?</strong></strong>.*?">.*?</a>"

Und schon wird das Fragezeichen auch als Fragezeichen interpretiert und nicht als Steuerungszeichen.  ;)

Ich hoffe das konnte dir ein wenig weiterhelfen.

Viele Grüße
Gordon

[vb.net] MDIchild Problem beim ändern der .text-Eigenschaft. Wird in .size nicht übernommen.

Das ist jetzt ein wenig kompliziert zu erklären. Ich bin auch nur darauf gestoßen weil die Software multilingual ist und ich Texte zur Laufzeit ändern muss.

Damit das Problem auftritt muss die Anwendung eine MDI Anwendung sein. Ändern wir nun zur Laufzeit im MDIchild z.B. den Text von Button1 (Me.Button1.Text = „Bla Bla“) dann funktioniert das auch wunderbar. Das Problem dabei ist das sich die Werte von Me.Button1.Size. nicht verändern. Das heißt der Button-Text ändert sich zwar, aber die Size-Eigenschaften nicht.

Das ist insofern ein Problem als das ich ja meist 2 Buttons habe. „Ok“ und „Abbrechen“ oder was auch immer. Nun ändere ich den Text im rechten Button und er wird dadurch kleiner oder größer (autosize = on). Damit das ganze trotzdem weiterhin schick aussieht, muss der linke Button nun so verschoben werden das der Abstand zwischen Button1 und Button2 wieder normal groß ist. Und genau hier brauche ich den neuen Me.Button1.Size.Width-Wert. Der aber immer noch der alte ist.

Die einzige Lösung die ich gefunden habe ist das die Texte der zu ändernden Elemente schon geändert werden müssen noch bevor man in der MDIform das Child öffnet. Dann werden die Werte auch schon beim Laden des Childs geändert. Achso, das Problem ist nicht immer. In der Form-Resize Funktion z.B. ändern sich die Werte ordnungsgemäß. Beim Load allerdings nicht.

Ich denke das Problem werden nur sehr wenige haben, wer ändert schon zur Laufzeit die Texte in Elementen. Aber vielleicht der ein oder andere schon.
Das wäre also eine mögliche Lösung. Hast du noch eine andere, bessere? Dann schreib doch bitte einen Kommentar und zeige uns deine Lösung. Danke.

[VB.NET] Datagridview – Schriftfarbe oder Hintergrundfarbe einer einzelnen Zelle ändern

Problem des Tages heute: Eine einzelne Zelle in einem Datagridview farbig ändern. Egal ob Schriftfarbe oder Hintergrundfarbe.

Schon mal versucht? Geht gar nicht so einfach. Das habe ich auch ganz schnell rausgefunden. Es gibt zwar die Style Eigenschaften, wenn man sich die Zelle mit Me.Datagridview1.Rows(0).Style… vorknöpft. Doch bewirkt eine Änderung hier nicht viel. Erst die letzte bzw. erste neue Zelle wird damit eingefärbt. Nicht aber die Zelle die man eigentlich einfärben möchte.

Und so habe ich heute stundenlang hin und her experimentiert, Google befragt, mich durch etliche Foren belesen, kuriose Klassen ausprobiert… und es am Ende doch selbst gemacht.

Leider ist es ein sehr mühsamer Weg, wenn man einer einzigen besch*** Zelle sagen will “Mache mal den Text Rot!”. Denn man muss das komplette Datagridview manuell anlegen. Ich arbeite ja generell ohne Databindings. Ja, fragt mich nicht warum, ich mache es halt :-) Nur war es bis dato einfach zu sagen Me.Datagridview1.Rows.Add(„Text 1“, „Text 2“, 1, 2, 3, etc.)

Jetzt wird das ganze nicht mehr so einfach. Jetzt müssen wir jede Zelle wirklich einzeln anlegen, denn nur so können wir auf die konkreten Zelleigenschaften zugreifen und auch setzen.
Ok, wie geht es konkret.

Dim DGVRow As New DataGridViewRow 
Dim Cell As DataGridViewCell 

'Eine normale Zelle 
Cell = New DataGridViewTextBoxCell 
Cell.Value = "Ein Text zum Testen" 
DGVRow.Cells.Add(Cell) 

'Eine Zelle mit rotem Text 
Cell = New DataGridViewTextBoxCell 
Cell.Value = "Ein roter Text zum Testen" 
Cell.Style.ForeColor = Color.Red 
DGVRow.Cells.Add(Cell) 

Me.Datagridview1.Rows.Add(DGVRow)

Was machen wir hier? Wir definieren eine einzelne Datagridview-Zelle und weisen dieser alle nötigen Werte zu. Im Normalfall einfach nur den Value. Aber man kann ihr jetzt auch eine Schriftfarbe zuweisen oder eine Hintergrundfarbe, Schriftart und alles weitere.
Dann packen wir die Zelle in einen Datagridview-Row (DGVRow) und können Sie danach neu Formatieren und neu Belegen, mit der nächsten Zelle. Die dann auch wieder in das Row-Element… bis alle Zellen für ein Row voll sind. Das vollständige DGVRow weisen wir letztendlich dem Me.Datagridview.Row.Add zu. Fertig…

… mit einer Zeile. Das müssen wir jetzt für alle Zeilen machen die dem Datagridview hinzugefügt werden sollen. Daher ist meine Empfehlung das ganze einer Funktion zuzuweisen oder noch besser einer Class. Das hier soll ja nur zur Orientierung dienen wie es funktioniert.

Sehr umständlich, aber funktioniert. Und das ohne fremde Klasse. ;-)

Update: Ich korrigiere. Auch mit Me.Datagridview1.Rows(0).Cells(0).Style.ForeColor = … lässt sich die Schriftfarbe verändern. Nur warum es mal funktioniert und mal nicht… das muss ich noch ergründen. Als einfach ausprobieren. Wenn es so funktioniert, dann kann man sich den komplizierteren Weg oben sparen.

[VB.NET] NotifyIcon mit Transparenz

Hallo,

heute mal ein kleiner Codeschnipsel zum Thema NotifyIcon mit Transparenz.

Ich habe nicht rausgefunden wie man normal ein *.ico mit Transparenz hinbekommen. Zumindest hat es mein Programm nicht unterstützt. Also habe ich mir einen kleinen Code gebastelt der ein bisschen rumtrickst. :-) Damit kann man auch noch sicher andere Sachen basteln.

Funktionieren tut es ganz einfach. In meinem Fall habe ich eine ImageList die diverse Bilder beinhaltet. Daraus suche ich einfach eines raus und lasse es als NotifyIcon setzen.

Die Sub dazu sieht dann so aus. Muss natürlich noch mit dem Programmstart ausgeführt werden.

' sets a new icon from the imagelist. because of the transparens
    Sub createNotifyIcon()
        Try
            Dim img As Bitmap = Me.ImageList1.Images(1)
            Dim hIcon As IntPtr = img.GetHicon()
            Dim icn As Icon = Drawing.Icon.FromHandle(hIcon)
            Me.NotifyIcon1.Icon = icn
            icn = Nothing
            hIcon = Nothing
            img = Nothing
        Catch exc As Exception
            'ups, error... hope the icon is still there...
        End Try
    End Sub