Tipp-Upload: VB.NET 0257: Flexible Settings
von Spatzenkanonier
Ü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.
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 |
Verwendete API-Aufrufe: |
Download: |
' 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.