CustomControl: GControlBox - Eine ControlBox mit eigenen Schaltflächen und mehr

    • VB.NET
    • .NET 4.0

    Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von Gather.

      CustomControl: GControlBox - Eine ControlBox mit eigenen Schaltflächen und mehr

      Hallo zusammen!
      Ich melde mich wieder mit einem neuen Projekt von mir. Und, dadurch, dass es sich um ein Projekt von mir handelt, ist dieses natürlich auch ein Designprojekt.
      Diesmal wieder Open-Source, und dadurch hier im Sourcecode-Austausch.
      Das Steuerelement, welches ich in diesem Thread vorstellen möchte, ist eine Controlbox für WinForms Anwendungen.

      Hintergrundinfo
      Was ist eine ControlBox und für was benötigt man sie?
      Grundsätzlich handelt es sich hierbei um einen von mir "kreirten" Namen für die Schaltflächen jedes Windows Fensters (oben rechts).
      Ich spreche von den Köpfen Minimieren, Maximieren und Schließen. Natürlich gibt es diese Schaltflächen in jeder Windows Forms Anwendung schon.
      Wenn man jedoch das Form Design anpassen möchte, wie es diverse Programme(auch größere Anwendungen - Paradebeispiel Visual Studio -) schon machen,
      kann man nun auf dieses CustomControl zurückgreifen. Besonders bei Anwendungen mit dem FormBorderStyle = None ist dies ganz praktisch.

      Ich hatte dieses Control schoneinmal programmiert, undzwar in meinem Projekt der MetroSuite, jedoch dort eher unschön und nicht wirklich auf die Ansprüche des Developers anpassbar.
      Deswegen habe ich mich in den vergangenen Tagen rasch hingesetzt und etwas neues zusammengebastelt (welches später in die MetroSuite implementiert wird).

      Vorraussetzungen
      Das CustomControl benötigt keine besonderen Vorraussetzungen, lediglich .NET Framework 4.0 wobei es vermutlich nichteinmal davon abhängig ist.
      Es wurde zwar mit diesen Einstellungen programmiert, kann jedoch nach unten gesetzt werden.

      Inspiration
      Inspieriert wurde dieses CustomControl, wie oben schon angedeutet, von der ControlBox von VisualStudio.
      Ich persönlich habe mich mehr oder weniger in das Dark-Theme verliebt, und habe deshalb dieses nachgebaut.
      Meine Vorlage für das Steuerelement war also folgende:



      Code-Dekontruktion
      Werfen wir nun einen kleinen Blick auf den beigelegten Code, unzwar eigentlich nur auf die Zeichenmethode.

      VB.NET-Quellcode

      1. 'Draw Areas
      2. If _Areas.Count > 0 Then
      3. For i As Integer = 0 To _Areas.Count - 1
      4. Dim c As Color = _ControlBoxAreas(i).DefaultColor
      5. g.FillRectangle(New SolidBrush(c), _Areas(i))
      6. ' g.DrawRectangle(Pens.Aqua, _Areas(i))
      7. If _Areas(i) <> _HotArea Then
      8. ' Draw Icon
      9. Select Case _ControlBoxAreas(i).AreaType
      10. Case ControlBoxAreaType.Custom : If _ControlBoxAreas(i).AreaImage IsNot Nothing Then g.DrawImage(_ControlBoxAreas(i).AreaImage, GetCenterPoint(_ControlBoxAreas(i).AreaImage, _Areas(i)))
      11. Case ControlBoxAreaType.Close : DrawIcon(g, Color.White, ControlBoxAreaType.Close, _Areas(i), c)
      12. Case ControlBoxAreaType.Minimize : DrawIcon(g, Color.White, ControlBoxAreaType.Minimize, _Areas(i), c)
      13. Case ControlBoxAreaType.Maximize : DrawIcon(g, Color.White, ControlBoxAreaType.Maximize, _Areas(i), c)
      14. End Select
      15. Using p As New Pen(_ControlBoxAreas(i).HighlightColor)
      16. If _ControlBoxAreas(i).IsHighlighted Then g.DrawLine(p, New Point(_Areas(i).X, _Areas(i).Y + _Areas(i).Height - 1), New Point(_Areas(i).X + _Areas(i).Width - 1, _Areas(i).Y + _Areas(i).Height - 1))
      17. End Using
      18. End If
      19. Next
      20. End If



      In diesem Abschnitt werden alle Felder, außer das indem sich derzeit die Maus befindet, gezeichnet. Grundsätzlich ist dies auch schnell erklärt:
      Eine Liste aller Felder (_Areas [List Of Rectangle]) wird durchgelaufen. Dabei wird von jedem die jeweilige Standardfarbe ausgewählt,
      und im Anschluss, -sofern vorhanden- das dazugehörige Icon gezeichnet. Die Select Case ()-Abfrage dient zum Zeichnen der Standardicons (Minimieren, Maximieren und Schließen),
      welche in der Methode DrawIcon gezeichnet werden. Welches Icon gezeichnet werden soll kann immer beim Erstellen eines neues Feldes mit der Eigenschaft AreaType festgelegt werden. Wird ein eigenes Icon gezeichnet ist dieser Wert "Custom".
      Zuletzt wird noch abgefragt ob die Eigenschaft IsHighlighted für das Feld true ist. Wenn ja wird noch ein kleiner Farbakzent gezeichnet.

      Nun muss noch das Feld gezeichnet werden in dem sich die Maus befindet. Die Position der Maus, sowie deren derzeitigen Status wird in der Mouse-Hook ermittelt.
      Dort werden alle Felder durchlaufen, und sofern die Position in einem dieser liegt weitergegeben und neugezeichnet. In der Paint-Methode wird anschließend das Feld dargestellt:

      VB.NET-Quellcode

      1. 'Draw Hot Area
      2. If _HotArea <> Nothing Then
      3. Using p As New Pen(Brushes.Red)
      4. Using b As New SolidBrush(_ControlBoxAreas(_HotIndex).HoverColor)
      5. Select Case (_MouseState)
      6. Case Helpers.MouseState.Over : p.Color = Color.Red : b.Color = _ControlBoxAreas(_HotIndex).HoverColor
      7. Case Helpers.MouseState.Pressed : p.Color = Color.DarkRed : b.Color = _ControlBoxAreas(_HotIndex).PressedColor
      8. End Select
      9. g.FillRectangle(b, _HotArea)
      10. ' g.DrawRectangle(p, _HotArea)
      11. ' Draw Icon
      12. Select Case _ControlBoxAreas(_HotIndex).AreaType
      13. Case ControlBoxAreaType.Custom : If _ControlBoxAreas(_HotIndex).AreaImage IsNot Nothing Then g.DrawImage(_ControlBoxAreas(_HotIndex).AreaImage, GetCenterPoint(_ControlBoxAreas(_HotIndex).AreaImage, _HotArea))
      14. Case ControlBoxAreaType.Close : DrawIcon(g, Color.White, ControlBoxAreaType.Close, _HotArea, b.Color)
      15. Case ControlBoxAreaType.Minimize : DrawIcon(g, Color.White, ControlBoxAreaType.Minimize, _HotArea, b.Color)
      16. Case ControlBoxAreaType.Maximize : DrawIcon(g, Color.White, ControlBoxAreaType.Maximize, _HotArea, b.Color)
      17. End Select
      18. End Using
      19. p.Color = _ControlBoxAreas(_HotIndex).HighlightColor
      20. If _ControlBoxAreas(_HotIndex).IsHighlighted Then g.DrawLine(p, New Point(_Areas(_HotIndex).X, _Areas(_HotIndex).Y + _Areas(_HotIndex).Height - 1), New Point(_Areas(_HotIndex).X + _Areas(_HotIndex).Width - 1, _Areas(_HotIndex).Y + _Areas(_HotIndex).Height - 1))
      21. End Using
      22. End If


      Das Verfahren ist prinzipiell genau das selbe wie bei den inaktiven Feldern. Folglich muss hier nichts besonderes erklärt werden.

      Wenn man das Steuerelement auf die Form zieht, sieht die Darstellung im Designer nicht so aus wie man es sich erwartet.
      Man sieht ein leeres Feld mit einem einem String. Dies ist so, da natürlich noch keine Felder zum Control hinzugefügt worden sind.
      Will man dies nicht, kann dies mit der Eigenschaft DesignModeControl deaktiviert werden.
      Um sich die Positionierung zu erleichtern, beziehungsweise wenn man keine eigenen Felder benötigt, kann man die Eigenschaft LoadDefaultAreas auf true setzen.
      Dadurch werden die drei Standardschaltflächen vorgeladen zum Control hinzugefügt und angezeigt.

      Hinzufügen einer Schaltfläche
      Das Hinzufügen einer Schaltfläche funktioniert relativ simpel.
      Man erstellt einfach eine neue ControlBoxArea-Struktur und fügt diese dem Control mittels der Methode .AddArea() hinzu.
      Dies kann wie folgt aussehen:

      VB.NET-Quellcode

      1. a1 = New ControlBox.ControlBoxArea(My.Resources.flag, New Size(32,32), Color.FromArgb(42, 42, 42), Color.FromArgb(72, 72, 72), Color.FromArgb(202, 81, 0), GathersControlBox.ControlBox.ControlBoxAreaType.Custom, "flag", true)
      2. a1.HighlightColor = Color.FromArgb(202, 81, 0)
      3. ControlBox1.AddArea(a1)

      Bei der New-Methode können folgende Parameter angegeben werden:
      1. AreaImage - Das Icon der Schaltfläche.
      2. AreaSize - Die Größe der Schaltfläche.
      3. DefaultColor - Die Standardfarbe der Schaltfläche.
      4. HoverColor - Die Hoverfarbe der Schaltfläche.
      5. PressedColor - Die Gedrücktfarbe der Schaltfläche.
      6. (optional) AreaType: Der Typ der Schaltfläche. (legt fest ob Standardicons gezeichnet werden sollen)
      7. (optional) AreaName: Der Name der Schaltfläche.
      8. (optional) HighlightArea: Gibt an, ob die Schaltfläche hervorgehoben werden soll.
      Aufgrund dieser vielen Anpassmöglichkeiten lassen sich viele schöne Zusatzschaltflächen, zu den Standard, hinzufügen, was in manchen Situationen ziemlich praktisch sein kann.

      Das Ergebnis
      Unser Ergebnis sieht nun wie folgt aus:


      Mit ein Bisschen Anpassen kann die Controlbox nun so aussehen. Man sieht ein modernes Steuerelement mit zusätzlichen Schaltflächen wie man sie von Visual Studio kennt.
      Der nächste Screenshot zeigt weniger Schaltflächen, dafür aber die [ttI]sHighlighted[/tt] Eigenschaft.


      Alles zusammen:


      Verwendung
      Nun müssen die Schaltflächen natürlich noch eine Funktion bekommen, da sie derzeit nur Deko sind.
      Dies geschieht mittels dem AreaClicked() Event, welches den Sender und ControlBoxEventArgs zurück gibt.
      Mit mehreren Methoden kann man nun den einzelnen Schaltflächen Funktionen zuweisen. Eine wäre zum Beispiel mit der Name-Eigenschaft,
      oder simpel mit dem jeweiligen Index:

      VB.NET-Quellcode

      1. Private Sub ControlBox1_AreaClicked(sender As Object, e As ControlBox.ControlBoxEventArgs) Handles ControlBox1.AreaClicked
      2. Select Case e.Item.Name
      3. Case "max"
      4. If WindowState = FormWindowState.Maximized Then
      5. WindowState = FormWindowState.Normal
      6. ElseIf WindowState = FormWindowState.Normal Then
      7. WindowState = FormWindowState.Maximized
      8. End If
      9. Case "min"
      10. WindowState = FormWindowState.Minimized
      11. Case "end"
      12. Application.Exit()
      13. End Select
      14. End Sub


      Kombinierungsmöglichkeiten
      Ein Bisschen Werbung möchte ich an dieser Stelle für zwei meiner Projekte machen.
      Man kann nämlich die Controlbox perfekt mit diesen kombinieren. Ich rede von meinem OpenSource Projekt SteamControls und natürlich von der MetroSuite.
      Beide findet ihr unter folgenden Links:
      SteamControls - Ein modernes DarkUI für deine Anwendung!
      MetroControls - Suite; Hohl dir den Windows 8 Style für deine Anwendung

      In diesem Sinne bedanke ich mich erneut für eure Aufmerksamkeit und hoffe, dass dieses Projekt jemandem weiterhelfen konnte.

      Liebe Grüße und Viel Spaß!

      Martin Pfeiffer aka. Gather_
      Dateien
      Mfg: Gather
      Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


      zunächstmal würde ich die Visual Studio - Empfohlene Einstellungen empfehlen.

      Ist immer eine wichtige Vorsichtsmassnahme.
      Keine Sorge: In deinem Fall kompiliert es sogar, und auch den Deppen-Namespace kann man rauswerfen und muss nur an einer Stelle nachbessern. :thumbup:

      Aber dann will ich son Ding mal auf ein UserControl ziehen, und erhalte sowas:
      Bilder
      • ControlboxFail.png

        29,67 kB, 486×597, 147 mal angesehen

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

      ErfinderDesRades schrieb:

      Aber dann will ich son Ding mal auf ein UserControl ziehen, und erhalte sowas:
      Ich hab zunächst aus beiden eine gemeinsame Projektmappe gemacht und hab alle Controls auf ne neue Form gezogen, da ist da nix passiert. :/
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      VB-Fragen über PN / Konversation werden ignoriert!

      ErfinderDesRades schrieb:

      UserControl
      Jou, das knallt.
      Im Code ruft @Gather FindForm.BackColor auf, da muss Parent.BackColor hin.
      Beim FindForm.WindowState muss erst bis zur Parent-Form durchiteriert werden.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      VB-Fragen über PN / Konversation werden ignoriert!
      jo, deswegen habich den Test gemacht: Weil auf UserControls bestehen ein paar Bedingungen anders als auf Forms.

      ZB FindForm() findet im DesignMode nichts, weil im DesignMode ists ja ohne Form.

      Aber auch die DesignMode-Property failt - die gibt auch im Designmode False zurück, wenn das CustomControl auf einem Ucl auf einem Form liegt. - wenn ich mich recht erinnere.
      Ja das wo das failt, ist im Prinzip nur eine Spielerei um die controlbox im Designer besser platzieren zu können.
      Mfg: Gather
      Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Gather“ ()