Die Community zu .NET und Classic VB.
Menü

Tipp-Upload: VB.NET 0315: Form-Design-Preferences

 von 

Über den Tipp  

Dieser Tippvorschlag ist noch unbewertet.

Der Vorschlag ist in den folgenden Kategorien zu finden:

  • Fenster
  • Menüs
  • Sonstiges
  • Steuerelemente

Dem Tippvorschlag wurden folgende Schlüsselwörter zugeordnet:
IExtenderProvider,Designer,canextend

Der Vorschlag wurde erstellt am: 24.09.2008 13:17.
Die letzte Aktualisierung erfolgte am 11.01.2009 12:36.

Zurück zur Übersicht

Beschreibung  

Form-Designer-Programmierung.
Die CanExtend-Methode der IExtenderProvider-Schnittstelle wird zur Designzeit aufgerufen. Das wird hier in 2-facher Weise ausgenutzt:

1) In einem HashSet (sehr schöne neue Klasse des FW3.5) werden alle Toolstrips gesammelt, also Menustrips, ContextMenustrips, Toolstrips. Beim Klick im Designer auf die "GenerateCode"-Property wird dann pro Toolstrip eine Sub generiert, die die _Click-Events aller im Toolstrip enthaltenen Buttons behandelt.

2) Bestimmte von MS eingestellte Voreinstellungen diverser Controls können evtl. nerven. Die FormPreferences-Klasse nutzt den CanExtend-Aufruf, um festzustellen, ob ein Control neu hinzugefügt wurde. Sodann stellt sie ggfs. die Voreinstellung um, auf den ihr einprogrammierten Wert.

FormPreferences ist erst nach Projekt-Erstellung in der Toolbox verfügbar.

Das ganze ist evtl. mit Makros oder AddIns besser zu lösen, aber wenn man nur VB-Express hat...
FormPreferences kann jederzeit auch wieder entfernt werden.

Schwierigkeitsgrad

Schwierigkeitsgrad 3

Verwendete API-Aufrufe:

Download:

Download des Beispielprojektes [17,85 KB]

' Dieser Source stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!
'
' Beachten Sie, das vom Designer generierter Code hier ausgeblendet wird.
' In den Zip-Dateien ist er jedoch zu finden.

' --------- Anfang Projektgruppe FormPreferences.sln ---------
' -------- Anfang Projektdatei FormPreferences.vbproj --------
' ---------------- Anfang Datei Extensions.vb ----------------
' IDE-Voreinstellungen:
' Option Strict On
' Option Explicit On
' Option Infer On

' Projekt-Voreinstellungen
' Imports System
' Imports System.Windows.Forms
' Imports System.Collections.Generic
' Imports Microsoft.VisualBasic.ControlChars
' Imports System.Linq

Imports System.Runtime.CompilerServices

Public Module Extensions

    ''' <summary> testet vor einer Zuweisung, ob der neue Wert überhaupt eine Änderung bringt </summary>
    ''' <remarks>
    ''' nützlich bei Zuweisungen an performance-intensive Properties, 
    ''' oder wenn auf Änderungen reagiert werden muß
    ''' </remarks>
    <Extension()> _
        Public Function Assign(Of T, T2 As T)(ByRef Dest As T, ByVal Src As T2) As Boolean

        If Object.Equals(Dest, Src) Then Return False
        Dest = Src
        Return True

    End Function

    <Extension()> _
        Public Sub ForEach(Of T)(ByVal Subj As IEnumerable(Of T), ByVal Action As Action(Of T))

        For Each O In Subj
            Action(O)
        Next

    End Sub

    ''' <summary> verkettet alles Strings, fügt Separator dazwischen ein </summary>
    <Extension()> Public Function ToStringX(ByVal Subj As IEnumerable(Of String), ByVal _
        Separator As String) As String

        With New System.Text.StringBuilder

            For Each S In Subj
                .Append(S).Append(Separator)
            Next

            If .Length > 0 Then
                .Remove(.Length - Separator.Length, Separator.Length)
            End If

            Return .ToString
        End With

    End Function

    ''' <summary> fügt ein Object-ParamArray als einen Gesamtstring hinzu </summary>
    <Extension()> _
        Public Sub AddX(ByVal Subj As ICollection(Of String), ByVal ParamArray Items() As Object)

        With New System.Text.StringBuilder
            Items.ForEach(Function(itm) .Append(If(itm, "##Null##")))
            Subj.Add(.ToString())
        End With

    End Sub

End Module

' ----------------- Ende Datei Extensions.vb -----------------
' ----------------- Anfang Datei frmMain.vb  -----------------

Public Class frmMain

    ' Den Code, der hier stehen könnte, möge man sich generieren lassen ;)

End Class

' ------------------ Ende Datei frmMain.vb  ------------------
' ------------- Anfang Datei FormPreferences.vb  -------------
Imports System.ComponentModel

Public Class FormPreferences

    Inherits Component
    Implements IExtenderProvider

    Private Shared _GenerateTabSize As Integer = 3
    Private _ToolStrips As New HashSet(Of ToolStrip)
    Private _NewControls As New HashSet(Of Control)

    ''' <summary>
    ''' Doppelklick im Designer auf diese Property löst Code-Generierung für ToolstripItems aus
    ''' </summary>
    <Browsable(True)> <Category("Verhalten")> <DefaultValue(False)> Public Property _
        GenerateCode() As Boolean

        Get
            Return False

        End Get

        Set(ByVal value As Boolean)

            If value Then ExecuteGenerateCode(_ToolStrips)

        End Set

    End Property

    <Browsable(True)> <Category("Verhalten")> <DefaultValue(3)> Public Property _
        GenerateTabSize() As Integer

        Get
            Return _GenerateTabSize

        End Get

        Set(ByVal value As Integer)
            _GenerateTabSize = value

        End Set

    End Property

    Public Function CanExtend(ByVal extendee As Object) As Boolean Implements _
        IExtenderProvider.CanExtend

        ' Toolstrips merken, für evtl. CodeGenerierung
        If TypeOf extendee Is ToolStrip Then _ToolStrips.Add(DirectCast(extendee, ToolStrip))

        ' Diese OrElse-Kette arbeitet prinzipiell gleich wie eine ElseIf-Kette: sobald eine der
        ' definierten Bedingungen matcht wird die Kette verlassen.
        ' Die Bedingung besteht darin, daß TryAction prüft, ob extendee vom angegebenen Typ ist,
        ' und der Delegat ist die dann einmalig auszuführende Preferenz.
        ' z.B. bei Labels willich .AutoSize=False haben, und von .HideSelection halte ich bei
        ' keinem Control etwas, und der voreingestellte Split-Balken des SplitContainers ist mir
        ' mit 4Pix viel zu schmal.
        Dim Dum = TryAction(extendee, Function(Obj As SplitContainer) _
            Obj.SplitterWidth.Assign(8)) OrElse TryAction(extendee, Function(Obj As Label) _
            Obj.AutoSize.Assign(False)) OrElse TryAction(extendee, Function(Obj As TreeView) _
            Obj.HideSelection.Assign(False)) OrElse TryAction(extendee, Function(Obj As _
            TextBoxBase) Obj.HideSelection.Assign(False)) OrElse TryAction(extendee, _
            Function(Obj As ListView) Obj.HideSelection.Assign(False))

    End Function

    ''' <summary> Falls Obj vom Typ T ist wird die Action(Of T) damit ausgeführt </summary>
    ''' <returns> True, falls Obj vom Typ T ist </returns>
    Private Function TryAction(Of T As Control)( _
              ByVal Obj As Object, ByVal Preference As Action(Of T)) As Boolean

        ' Nur für **neue** Controls dürfen die Preferenzen ausgeführt werden.
        ' neue Controls werden durch Test auf .Parent=Nothing identifiziert.
        ' leider ist für ToolstripItem keine Preferenz definierbar, da nicht von Control erbend.
        ' ToolstripItem hat auch keine Property mit der man neue Item identifizieren kann.
        TryAction = TypeOf Obj Is T

        If TryAction Then

            Dim Ctl = DirectCast(Obj, T)

            If Ctl.Parent Is Nothing Then
                _NewControls.Add(Ctl)

            Else

                If _NewControls.Remove(Ctl) Then Preference(Ctl)
            End If
        End If

    End Function

    Public Shared Sub ExecuteGenerateCode(ByVal _ToolStrips As HashSet(Of ToolStrip))

        Dim AllWriter As New List(Of String)
        Dim Clickables As New List(Of String)

        For Each CustomerStrip In _ToolStrips
            Clickables.Clear()

            For Each Itm As ToolStripItem In CustomerStrip.Items
                CollectClickables(Itm, Clickables)
            Next

            If Clickables.Count > 0 Then

                Dim sHandles = Clickables.ToStringX(".Click, ") & ".Click"
                Dim sCase = Tab & Tab & "case Sender Is "
                Dim sCases = sCase & Clickables.ToStringX(NewLine & NewLine & sCase) & NewLine

                With AllWriter

                    .AddX("Private Sub ", CustomerStrip.Name, "_MenuClicked(ByVal Sender " & _
                        "As Object, ByVal e As EventArgs) _")

                    .AddX(Tab, Tab, "Handles ", sHandles)
                    .AddX(Tab, "select case True")
                    .AddX(sCases)
                    .AddX(Tab, "End select")
                    .AddX("End Sub")
                    .AddX("")
                End With

            End If

        Next

        ' Die Ausgabe wird in eine TextDatei geschrieben, die dann geöffnet wird
        Dim S = AllWriter.ToStringX(NewLine).Replace(Tab, New String(" "c, _GenerateTabSize))
        Dim FileFullName As String = Environment.CurrentDirectory & "\LaunchEditorWith.txt"

        My.Computer.FileSystem.WriteAllText(FileFullName, S, False)
        System.Diagnostics.Process.Start(FileFullName).Dispose()

    End Sub

    Private Shared Sub CollectClickables(ByVal Itm As ToolStripItem, ByVal Clickables As _
        List(Of String))

        If TypeOf Itm Is ToolStripDropDownItem Then

            With DirectCast(Itm, ToolStripDropDownItem)

                If .HasDropDownItems Then

                    For Each itmRecurse As ToolStripItem In .DropDownItems
                        CollectClickables(itmRecurse, Clickables)        ' Rekursion!
                    Next

                    Return
                End If

            End With

            Clickables.Add(Itm.Name)

        ElseIf TypeOf Itm Is ToolStripButton Then

            Clickables.Add(Itm.Name)
        End If

    End Sub

End Class

' -------------- Ende Datei FormPreferences.vb  --------------
' --------- Ende Projektdatei FormPreferences.vbproj ---------
' ---------- Ende Projektgruppe FormPreferences.sln ----------

	

Diskussion  

Diese Funktion ermöglicht es, Fragen, die die Veröffentlichung des Tipps betreffen, zu klären, oder Anregungen und Verbesserungsvorschläge einzubringen. Nach der Veröffentlichung des Tipps werden diese Beiträge nicht weiter verlinkt. Allgemeine Fragen zum Inhalt sollten daher hier nicht geklärt werden.

Um eine Diskussion eröffnen zu können, müssen sie angemeldet sein.