Die Community zu .NET und Classic VB.
Menü

Tipp-Upload: VB.NET 0257: Flexible Settings

 von 

Über den Tipp  

Dieser Tippvorschlag ist noch unbewertet.

Der Vorschlag ist in den folgenden Kategorien zu finden:

  • Algorithmen
  • Sonstiges
  • Sprachmerkmale
  • Steuerelemente

Dem Tippvorschlag wurden folgende Schlüsselwörter zugeordnet:
Settings,Setting,inference,type-inference,TypeConverter

Der Vorschlag wurde erstellt am: 17.04.2008 00:51.
Die letzte Aktualisierung erfolgte am 27.01.2009 18:26.

Zurück zur Übersicht

Beschreibung  

ComplexConverter kann Werte beliebig komplexer Strukturen in einen String überführen und zurück. Der Witz ist, dass für beide Richtungen dasselbe Ereignis verwendet wird, in dem dann die Werte durchlaufen werden. Kombiniert mit einem Eintrag in den Settings kann man selbst Treeviews problemlos speichern und zum nächsten Programmstart wieder restaurieren. Da der Speicher-String keine Typ-Informationen enthält, ist er ca. 5 fach kompakter als etwa Xml.

Schwierigkeitsgrad

Schwierigkeitsgrad 3

Verwendete API-Aufrufe:

Download:

Download des Beispielprojektes [17,72 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 ComplexConverterDemo.sln  ------
' ----- Anfang Projektdatei ComplexConverterDemo.vbproj  -----
' ------------------ Anfang Datei Form1.vb  ------------------
' IDE-Voreinstellungen:
' Option Explicit On
' Option Strict On

' "My Project"-Einstellungen:
' Imports Microsoft.VisualBasic.ControlChars
' Imports System.Windows.Forms

Public Class Form1

    Private WithEvents _Memory As New ComplexConverter

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load

        ' My.Settings.Memory ist in den Anwendungseinstellungen eingerichtet
        ' wichtig: "Eigene Einstellungen beim Herunterfahren speichern" aktivieren!
        Dim S As String = My.Settings.Memory

        _Memory.ApplyDataString(S)

        ' RichTextBox nur zur Veranschaulichung - eigentlich nicht erforderlich
        RichTextBox1.Text = S

    End Sub

    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) _
                Handles Me.FormClosing

        My.Settings.Memory = _Memory.CreateDataString()

    End Sub

    ''' <summary>komplexe Konvertierung für dieses Form</summary>
    Private Sub _Memory_Convert(ByVal sender As Object, ByVal e As ComplexConverter.EventArg) _
        Handles _Memory.Convert

        ' Form-Properties konvertieren
        With Me
            e.ConvertValue(.WindowState)
            e.ConvertValue(.Bounds)
        End With

        ' Treeview konvertieren
        EnumerateNodes(TreeView1.Nodes, e)

        ' ListView-Spaltenbreiten konvertieren
        For Each Col As ColumnHeader In Me.ListView1.Columns
            e.ConvertValue(Col.Width)
        Next

        ' ListView-Items konvertieren
        e.ConvertList(Of ListViewItem)(ListView1.Items)

        For Each LVI As ListViewItem In ListView1.Items

            ' ListView-SubItems konvertieren
            e.ConvertList(Of ListViewItem.ListViewSubItem)(LVI.SubItems)

            For Each LVSI As ListViewItem.ListViewSubItem In LVI.SubItems
                e.ConvertValue(LVSI.Text)
            Next
        Next

    End Sub

    Private Sub EnumerateNodes(ByVal Nodes As TreeNodeCollection, ByVal e As _
        ComplexConverter.EventArg)

        e.ConvertList(Of TreeNode)(Nodes)

        For Each Nd As TreeNode In Nodes
            e.ConvertValue(Nd.Text)
            EnumerateNodes(Nd.Nodes, e)

            ' Workaround, da Treenode.IsExpanded readonly, also nicht direkt restaurierbar
            If e.IsStoring Then
                e.ConvertValue(Nd.IsExpanded)

            Else

                If e.GetValue(Of Boolean)() Then Nd.Expand()
            End If

        Next

    End Sub

    Private Sub Button_Click(ByVal sender As Object, ByVal e As EventArgs) Handles _
                btRead.Click, btWrite.Click, btAddNode.Click, btRemoveNode.Click, _
                btAddLVItem.Click, btRemoveListViewItem.Click

        Select Case True

            Case sender Is btRead
                _Memory.ApplyDataString(RichTextBox1.Text)

            Case sender Is btWrite
                RichTextBox1.Text = _Memory.CreateDataString

            Case sender Is btAddNode

                Dim Nd As TreeNode = TreeView1.SelectedNode

                If Nd Is Nothing Then
                    TreeView1.Nodes.Add("NewNode")

                Else

                    Nd.Nodes.Add("NewNode")
                    Nd.Expand()
                End If

            Case sender Is btRemoveNode

                Dim Nd As TreeNode = TreeView1.SelectedNode

                If Nd Is Nothing Then
                    MsgBox("Select a Node to remove")

                Else

                    Nd.Remove()
                End If

            Case sender Is btAddLVItem

                ' (N - Brimborium, um hübsch numerierte ListViewItems zu erhalten)
                Dim N As Integer = ListView1.Items.Count - 1

                If N >= 0 Then

                    With ListView1.Items(N).Text
                        N = Integer.Parse(.Substring(0, .Length - 1))
                    End With

                End If

                N += 1

                Dim LVI As ListViewItem = ListView1.Items.Add(String.Concat(N, "1"))

                For I As Integer = 2 To ListView1.Columns.Count
                    LVI.SubItems.Add(String.Concat(N, I))
                Next

            Case sender Is btRemoveListViewItem

                With ListView1.SelectedItems

                    If .Count = 0 Then
                        MsgBox("Select a ListViewItem to remove")

                    Else

                        ListView1.Items.RemoveAt(.Item(0).Index)
                    End If

                End With

        End Select

    End Sub

End Class

' ------------------- Ende Datei Form1.vb  -------------------
' ------------- Anfang Datei ComplexConverter.vb -------------
Imports Microsoft.VisualBasic
Imports System.ComponentModel

Public Class ComplexConverter

    ' Dieser Separator kann Fehler verursachen, wenn Text gespeichert wird, der '|' enthält
    ' Wird hier nur für die Demo verwendet
    Private Const Separator As Char = "|"c

    ' Dieser Separator ist sicher, aber nicht darstellbar in der Richtextbox
    ' Private Const Separator As Char = ChrW(&HF019)

    ''' <summary>
    ''' zeigt an, daß beim Restaurieren ein behandelbarer Fehler aufgetreten ist
    ''' </summary>
    Public Class RestoreException

        Inherits Exception

        Public Sub New(ByVal ex As Exception)

            MyBase.New("Restore failed", ex)

        End Sub

    End Class

    Public Class EventArg

        Inherits EventArgs

        ' Das Event ComplexConverter.Convert(), welches dieses EventArg verwendet, wird in zwei
        ' Modi ausgeführt:
        ' Store konvertiert einen gegebenen Wert und fügt der IList(Of String) einen Eintrag hinzu
        ' Restore re-konvertiert einen Eintrag und überschreibt damit den gegebenen Wert

        Private _VBProvider As VBCodeProvider
        Private _Strings As IList(Of String)
        Private _Counter As Integer = 0

        Public ReadOnly IsStoring As Boolean

        Sub New(ByVal Provider As VBCodeProvider, ByVal Strings As IList(Of String), _
                    ByVal IsStoring As Boolean)

            _VBProvider = Provider
            _Strings = Strings
            Me.IsStoring = IsStoring

        End Sub

        ''' <summary>Hier angegebene Werte werden gespeichert und restauriert</summary>
        <Description("Hier angegebene Werte werden gespeichert und restauriert")> _
            Public Sub ConvertValue(Of T)(ByRef Item As T)

            If IsStoring Then

                Dim S As String = _VBProvider.GetConverter(GetType(T)).ConvertToString(Item)

                If S.Contains(Separator) Then

                    Dim Msg As String = String.Concat("Der zu speichernde String '", S, _
                        "' darf nicht den ComplexConverter.Separator-Char (", _
                        System.Convert.ToString(AscW(Separator), 16), ") enthalten.")

                    Throw New ArgumentException(Msg, "Item")
                End If

                _Strings.Add(S)

            Else

                Item = GetValue(Of T)()
            End If

        End Sub

        ''' <summary>gibt einen gespeicherten Wert zurück</summary>
        <Description("gibt einen gespeicherten Wert zurück")> _
            Public Function GetValue(Of T)() As T

            If IsStoring Then

                Throw New Exception(".GetValue() darf nicht aufgerufen werden, wenn " & _
                    ".IsStoring = True.")

            Else

                Try

                    Dim C As TypeConverter = _VBProvider.GetConverter(GetType(T))

                    GetValue = DirectCast(C.ConvertFromString(_Strings(_Counter)), T)

                Catch ex As Exception

                    Throw New RestoreException(ex)

                End Try

                _Counter += 1
            End If

        End Function

        ' Sonderfall ConvertList(): Bei Listen wird die Anzahl Count der Elemente gespeichert.
        ' Restore leert die Liste und fügt dann Count uninitialisierte Elemente hinzu.

        ''' <summary>speichert Anzahl, restauriert mit uninitialisierten Elementen</summary>
        <Description("speichert Anzahl, restauriert mit uninitialisierten Listenelementen")> _
            Public Sub ConvertList(Of TItem As New)(ByVal List As IList)

            If IsStoring Then
                _Strings.Add(List.Count.ToString)

            Else

                List.Clear()

                Try

                    For I As Integer = 0 To Integer.Parse(_Strings(_Counter)) - 1
                        List.Add(New TItem)
                    Next

                Catch ex As Exception

                    Throw New RestoreException(ex)

                End Try

                _Counter += 1
            End If

        End Sub

        Public Sub ConvertConverter(ByVal Converter As ComplexConverter)

            ' ComplexConverters listigste Zeile: ermöglicht, den Konvertierungs-Vorgang an einen
            ' anderen Converter abzugeben, dabei aber "meine" _Strings zu verwenden. So kann ein
            ' UserControl aus einer anderen Assembly seine eigene Konvertierung definieren, die
            ' dann in den Settings der Entry-Assembly mit-persistiert wird
            Converter.OnConvert(Me)

        End Sub

    End Class ' ComplexConverter.EventArg

    Public Event Convert As EventHandler(Of EventArg)

    Private Sub OnConvert(ByVal e As EventArg)

        RaiseEvent Convert(Me, e)

    End Sub

    Public Function CreateDataString() As String

        Dim Strings As New List(Of String)

        Using VBProvider As New VBCodeProvider

            ' Store: Die im Ereignishandler angegebenen Items mit vom VBProvider erhaltenen
            ' TypeConvertern nach Strings konvertieren
            RaiseEvent Convert(Me, New EventArg(VBProvider, Strings, True))
        End Using

        Return String.Join(Separator, Strings.ToArray)

    End Function

    Public Sub ApplyDataString(ByVal S As String)

        If S = "" Then Return

        Dim Backup As New List(Of String)

        Using VBProvider As New VBCodeProvider

            ' Ist-Zustand ins Backup speichern
            OnConvert(New EventArg(VBProvider, Backup, IsStoring:=True))

            Try

                ' Restaurierung anhand von S versuchen
                OnConvert(New EventArg(VBProvider, S.Split(Separator), False))

            Catch Ex As RestoreException

                ' Im Fehlerfall Re-Restaurierung anhand des Backups
                OnConvert(New EventArg(VBProvider, Backup, False))

            End Try
        End Using

    End Sub

End Class

' -------------- Ende Datei ComplexConverter.vb --------------
' ------ Ende Projektdatei ComplexConverterDemo.vbproj  ------
' ------- Ende Projektgruppe ComplexConverterDemo.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.