Wo legt ihr euren Konfigurations XML ab?

  • VB.NET

Es gibt 23 Antworten in diesem Thema. Der letzte Beitrag () ist von bk__.

    Wo legt ihr euren Konfigurations XML ab?

    Hallo zusammen,
    ich schriebe gerade ein kleines portables Tool (.exe), in dem man gewisse Konfigurationen vornehmen & abspeichern kann.
    Damit die Konfiguration nach dem neu start der .exe Datei gespeichert bleibt, will ich die Konfiguration in eine XML Datei schreiben.

    Nun, da mein Tool kein Setup.exe hat, sondern ein portables Tool ist, muss ich die XML Datei irgendwo abspeichern. Was würdet ihr mir empfehlen? Wo sollte ich die XML Datei abspeichern?

    OS -> Windows 7
    Das Tool ist zwar portable, jedoch macht es mehr Sinn, wenn man sich die exe lokal zieht.
    Beim ersten start, sollte man einmal die Konfiguration anpassen, dann soll bei jedem Start die Config aus der XML Datei (falls vorhanden) ziehen.

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

    @bk__: Dein Programm ist portabel. Also ist AppData sicherlich nicht die richtige Stelle, um Programmeinstllungen zu speichern. Denn dann sind diese ja von Computer zu Computer unterschiedlich.

    Nimm das Programmverzeichnis.
    Erstelle da drin sowas wie eine Settings.xml oder ähnlich.
    Meistens hat man ja Standardeinstellungen. Wenn die XML-Datei beim Programmstart noch nicht existiert, speicherst Du einfach die Standardeinstellungen ab.
    Ansonsten lädst Du die XML-Datei.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    @Niko Ortner

    Mhhh... Also wenn ich das ganze als Standardeinstellung bereits angeben möchte.. muss ich ja im Load event bereits beim ersten Start einen Ordner im Programmverzeichnis erstellen mit einer XML... und bei jedem Programm Load abfragen, ob das Programmverzeichnis exisitert oder nicht.
    Würdest du auch so machen???
    ... ja? Ich denke ich habe nicht ganz richtig verstanden, wie Du das gemeint hast.
    Bei mir sieht's ausgedünnt auf das Nötigste üblicherweise so aus:

    VB.NET-Quellcode

    1. Class <HauptForm des Programms>
    2. Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
    3. LoadSettings() 'Beim Laden der Form die Einstellungen laden.
    4. MyBase.OnLoad(e)
    5. End Sub
    6. Protected Overrides Sub OnClosing(ByVal e As System.ComponentModel.CancelEventArgs)
    7. SaveSettings() 'Beim Beenden des Programmes die Einstellungen speichern.
    8. MyBase.OnClosing(e)
    9. End Sub
    10. Private Sub SaveSettings()
    11. Dim SB As New System.Text.StringBuilder 'Jetzt nur als Beispiel.
    12. SB.AppendLine(...)
    13. '....
    14. 'Existiert der Ordner, in dem die Einstellungen gespeichert sind nicht, muss er vorher erstellt werden.
    15. If Not System.IO.Directory.Exists(Settings.IO.SettingsDirectoryPath) Then
    16. System.IO.Directory.CreateDirectory(Settings.IO.SettingsDirectoryPath)
    17. End If
    18. 'Einstellungen speichern.
    19. System.IO.File.WriteAllText(Settings.IO.SettingsFilePath, SB.ToString, System.Text.Encoding.Default)
    20. End Sub
    21. Private Sub LoadSettings()
    22. 'Wenn die Einstellungsdatei nicht existiert, werden die Standardeinstellungen abgespeichert (damit die Datei konsistenzhalber existiert).
    23. If Not System.IO.File.Exists(Settings.IO.SettingsFilePath) Then
    24. SaveSettings()
    25. 'Das erneute Lesen der Einstellungen entfällt, weil ja sowieso schon die Standardeinstellungen vorhanden sind.
    26. Exit Sub
    27. End If
    28. For Each i In System.IO.File.ReadAllLines(Settings.IO.SettingsFilePath, System.Text.Encoding.Default)
    29. 'Auch hier nur als Beispiel
    30. Next
    31. End Sub
    32. End Class

    Die Kommentare sollten das Ganze ausreichend erklären.

    Auffällig ist die Klasse Settings mit der geschachtelten Klasse IO.
    Diese Klasse enthält einige statische Eigenschaften, die für die Arbeit mit dem Dateisystem notwendig sind.
    Die beiden Eigenschaften, die hier verwendet werden, sind "SettingsDirectoryPath" und "SettingsFilePath".
    Die Namen dieser Eigenschaften sind existenziell wichtig. Denn sie erlauben es, im restlichen Programm die Eigenschaften ohne Bedenken verwenden zu können. Man muss also später nicht mehr wissen, was denn tatsächlich der Einstellungsordner ist. Das übernimmt nämlich die Settings.IO-Klasse.
    Also: SettingsDirectoryPath gibt den Ordner an, in dem Einstellungen gespeichert werden. Und SettingsFilePath gibt die Datei an, in der die Programmeinstellungen gespeichert werden.
    In meinem Fall sind in diesem Ordner noch mehr Dateien vorhanden. Für die gibt's dann eigene Eigenschaften. Beispielsweise TreeFilePath. Die TreeFile beinhaltet einen Baum (lol), eine Verzeichnisstruktur.

    Dieses Konzept lässt sich auch auf andere Dateien und Ordner anwenden. Beispielsweise könnte es für ein PlugIn-System eine PlugInDirectoryPath-Eigenschaft geben. Diese gibt dann den Ordner an, in dem die PlugIns hinterlegt sind. Und im restlichen Programm muss man sich dann nie mehr darum kümmern, welcher Ordner das tatsächlich ist. Wenn man die PlugIns auslesen will, nimmt man einfach System.IO.Directory.GetFiles(Settings.IO.PlugInDirectoryPath). Und schon bekommt man die PlugIns aufgelistet, ohne dass man noch irgendwelche Pfade zusammenstellen muss.




    Damit das ordentlich funktioniert, muss man einmal ein bisschen Gehirnschmalz in die Settings.IO-Klasse investieren.

    VB.NET-Quellcode

    1. Public Class Settings
    2. Public Class IO
    3. 'Hier sind konstante Sachen aufgelistet. Beispielsweise Dateinamen.
    4. 'Beachte, dass bei Dateinamen/Ordnernamen immer "FileName"/"DirectoryName" steht, und nicht "FilePath"/"DirectoryPath". Das zeigt an, dass es sich nicht um den gesamten Pfad zur Datei / zum Ordner, sondern eben nur um den Dateinamen/Ordnernamen handelt.
    5. Public Const SettingsSubDirectoryName As String = "ApplicationSettings"
    6. Public Const SettingsFileName As String = "Settings.xml"
    7. 'Hier sind variable Sachen aufgelistet. Also die Dinge, die erst bekannt sind, nachdem das Programm gestartet wurde.
    8. 'Die Properties sind unter diesem Code erklärt.
    9. Public Shared ReadOnly Property ... As String
    10. * SettingsDirectoryPath
    11. * SettingsFilePath
    12. 'Der statische Konstruktor wird ausgeführt, sobald das erste Mal auf irgendwas dieser Klasse zugegriffen wird.
    13. 'Also wenn im ersten Code in Zeile 27 zum ersten Mal eine Pfadangabe abgefragt wird, dann dann wird dieser Code ausgeführt.
    14. Shared Sub New()
    15. Dim ApplicationFilePath = Application.ExecutablePath
    16. 'Die Compiler-Konstante CONFIG gibt die aktuelle Compiler-Konfiguration an.
    17. 'Wenn Du die nächsten 3 Zeilen nicht auskommentierst, wird beim Debuggen die Dateien im Release-Ordner genommen, anstelle der Dateien im Debug-Ordner. Das kann manchmal nützlich sein.
    18. #If CONFIG = "Debug" Then
    19. ApplicationFilePath = ApplicationFilePath.Replace("bin\Debug", "bin\Release")
    20. #End If
    21. Dim ApplicationDirectoryPath = System.IO.Path.GetDirectoryName(ApplicationFilePath)
    22. _SettingsDirectoryPath = System.IO.Path.Combine(ApplicationDirectoryPath, SettingsSubDirectoryName)
    23. _SettingsFilePath = System.IO.Path.Combine(_SettingsDirectoryPath, SettingsFileName)
    24. End Sub
    25. End Class
    26. End Class

    Alle Properties sind nach dem selben Prinzip aufgebaut:

    VB.NET-Quellcode

    1. Private Shared _PropertyName As String
    2. Public Shared ReadOnly Property PropertyName As String
    3. Get
    4. Return _PropertyName
    5. End Get
    6. End Property

    Also wenn oben im Code das steht:

    VB.NET-Quellcode

    1. Public Shared ReadOnly Property ... As String
    2. * SettingsDirectoryPath
    3. * SettingsFilePath
    , dann sind damit die gerade gezeigten Implementierungen gemeint, nur halt eben statt PropertyName die aufgelisteten Namen (SettingsDirectoryPath und SettingsFilePath)
    Zugriffe von außen auf Felder sollten immer über Properties gehandhabt werden.
    Es gibt im gesamten Framework nur wenige Ausnahmen. Beispielsweise EventArgs.Empty.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

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

    ich würde niemals eine Klasse Settings nennen, denn es gibt bereits ein global zugreifbares Settings-Objekt vom Typ MySettings, und gehört zu den grundlegenden Konzepten von .Net-Desktop-Anwendungen.
    Wennde sowas ähnliches selber basteln willst - vermeide Begriffs-Verwechslungen.
    @ErfinderDesRades: Klassen, die ähnliche Aufgaben haben, habe ich in anderen (späteren) Anwendungen GlobalSettings genannt.
    Settings alleine klang mir etwas abstrakt. ApplicationSettings wäre auch denkbar gewesen.
    Hast Du ein paar Infos zu diesem Settings-Objekt? Denn ich kenne das jetzt nur aus C# (Properties.Settings).
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    naja, in den Projekteigenschaften gesetzt ein Settings namens "aInt", dann code ich:

    VB.NET-Quellcode

    1. Dim test = My.Settings.aInt
    Ich kann auch "zu Definition gehen", dann komme ich hier raus (generierter Code):

    VB.NET-Quellcode

    1. Namespace My
    2. <Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
    3. Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
    4. Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
    5. Friend Module MySettingsProperty
    6. <Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
    7. Friend ReadOnly Property Settings() As Global._A0FormTests.My.MySettings
    8. Get
    9. Return Global._A0FormTests.My.MySettings.Default
    10. End Get
    11. End Property
    12. End Module
    13. End Namespace
    Ach so war das gemeint.
    Man muss an der Stelle dazu sagen, dass Settings dann nicht ganz global, sondern nur im My-Namespace zu finden ist.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Jo, wennich drüber nachdenke - zu Compiler-Fehlern wird das wohl nicht führen, solange My nicht importiert wird, oder du deine Settings im My-Namespace anlegst.
    Aber trotzdem - wenn ich "Settings" lese, dann denke ich zunächstmal, dass die MySettings gemeint sind. Sogar bei "GlobalSettings" täte ich das denken, weil beim Lesen binnich ziemlich schlampig :whistling: .
    Also ich zweifle ja so ein Bisschen an der Sinnhaftigkeit des My-Namespaces. Hätte man das nicht etwas konsistenter einbauen können?
    Ich meine... Wenn ich irgendwo im Code das habe:

    VB.NET-Quellcode

    1. Namespace My
    2. Public Class Settings
    3. End Class
    4. End Namespace
    , dann funktioniert folgendes nicht mehr:

    VB.NET-Quellcode

    1. Sub Foo()
    2. My.Settings.aInt = 0
    3. End Sub

    Stattdessen muss das verwendet werden:

    VB.NET-Quellcode

    1. Sub Foo()
    2. My.MySettings.Default.aInt = 0
    3. End Sub

    Was im Endeffekt auch das Selbe ist, wie Du oben mit dem Codeausschnitt gezeigt hast (Man überspringt halt einen Funktionsaufruf). Und wegen dem Global.Microsoft.VisualBasic.HideModuleNameAttribute muss man wohl den Modulnahmen nicht angeben. Wird nur schwierig, wenn es Namenskollisionen gibt.

    Ich weiß nicht so recht. Das hätte man sicher besser lösen können.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Niko Ortner schrieb:

    wegen dem Global.Microsoft.VisualBasic.HideModuleNameAttribute muss man wohl den Modulnahmen nicht angeben.
    Ich weiß ühaupt nicht, was HideModuleName bewirkt. Weil den Modulnamen muss man in VB leider eh nie angeben - das ist der Unterschied zur c#-static Class.

    Das führt dazu, dass alle in VB.Net notierten Extension-Methods auch als globale Methode die Intellisense vollmüllen, statt dasse - wie in c# - erst als Objektmethoden dort auftauchen.

    ErfinderDesRades schrieb:

    Weil den Modulnamen muss man in VB leider eh nie angeben

    Da hast Du recht.
    Ich hätte jetzt gedacht, dass man beispielsweise bei sowas:

    VB.NET-Quellcode

    1. Namespace Foo
    2. Public Module FooModule
    3. Public Property Bar As Integer
    4. End Module
    5. End Namespace
    , wenn man Foo.Bar aufrufen möchte, explizit Foo.FooModule.Bar angeben muss. Aber da lag ich falsch. Foo.Bar geht auch problemlos.
    Dann stellt sich wirklich die Frage nach dem Sinn dieses Attributs.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    @Niko Ortner

    Vielen Dank für deine ausführliche Antwort. Mit den Kommentaren ist auch sehr verständlich.
    Jedoch wenn den Code bei mir im Projekt kopiere, akzeptiert er "Settings" nicht (zeile 18, 19 22 etc.) Es kommt immer Names Settings is not declared.

    Weiss du vielleicht was der Grund sein könnte.

    LG
    bk