Hallo Community!
Diese kleine Projekt zeigt, wie man seine Settings an seine eigene Bedürfnisse angepasst persistiert.
(Entstehungsgeschichte)
Anforderung:
Man soll die Settings genauso handhaben können, wie es der Standard im VS vorsieht:
UserSettingsProvider
Die Schnittstelle
Dann bleiben die Schnittstellen-Member (
Dieser Provider wird einfach einem Projekt mitgegeben und ein Verweis angelegt.
Bei der Version DirectorySettingsProvider kann man sogar den Persistierpfad außerhalb des Providers benutzerdefiniert angeben...
Wichtig:
Der Provider wird entweder, wie unten gezeigt, in der Settings.vb den Settings vorgelegt.
Man geht auf die Seite
wird im My-Namespace eine Partial Class des Designercodes erzeugt, in der man dann das Attribut für den UserSettingsProvider angeben kann (der Provider ist dann für alle Settings zuständig)...
Oder man gibt den einzelnen Settings bei der Eigenschaft
Dann werden nur die extra gekennzeichneten Settings benutzerdefiniert gespeichert - die anderen werden wie üblich persistiert...
Man könnte auch verschiedene Provider, die dem Projekt verwiesen sind, der einzelnen Settings zuordnen.
DemoSolution:
Da werden die Eigenschaften Form.Location und die Form.ClientSize als Settings gebunden.
Zum Weiteren sind noch einige Controls zur Veranschaulichung dargestellt.
Der Pfad zur application.config.dat ist in diesem Projekt im Anwendungspfad festgelegt. Dieser kann individuell angepasst werden...
Diesen Provider kann man sich als Vorlage nehmen und an seine Bedürfnisse anpassen...
Danke an:
@ErfinderDesRades : für seine Vorschläge und Einwände
@RodFromGermany : Hinweis bei Benutzung mehrerer Anwendungen, die den gleichen Provider verwenden
Anbei jetzt die letzte Version der korrigierten DemoSolution.
Diese kleine Projekt zeigt, wie man seine Settings an seine eigene Bedürfnisse angepasst persistiert.
(Entstehungsgeschichte)
Anforderung:
Man soll die Settings genauso handhaben können, wie es der Standard im VS vorsieht:
- automatisches Speichern bei Beenden der App.
- mit dem Settingsdesigner Eigenschaften anlegen und Typen auswählen können
- ApplicationSettings binden können
- den Designer beim Binden verwenden können
- Der Provider kann zeitgleich von mehreren Anwendungen verwendet werden - jede Anwendung hat dann seine eigene Settingsdatei!
- ...
VB.NET-Quellcode
- Imports System.Configuration
- Imports System.ComponentModel
- Imports System.Reflection
- Imports System.IO
- Imports System.Collections.Specialized
- Imports System.Runtime.Serialization.Formatters.Binary
- Namespace MyProvider
- ''' <summary>
- ''' Dieser Provider speichert die betroffenen Settings-Einstellungen in eine eigene .exe.config.xml-Datei.
- ''' Diese Datei liegt im Arbeitsverzeichnis der Anwendung.
- ''' HINWEISE:
- ''' Die ApplicationName-Property erstellt die ProduktName-Eigenschaft von der My.Application.Info.ProduktName
- ''' Hier sollte in den Projekteigenschaften/Anwendung/Assemblyinformationen die Eigenschaft ProduktName = AssemblyName gestellt sein!
- ''' </summary>
- ''' <remarks></remarks>
- Public Class UserSettingsProvider
- Inherits SettingsProvider
- Implements IApplicationSettingsProvider
- Private Datas As Dictionary(Of String, Object)
- Private Property DataFile As FileInfo
- Private Property AppPath As String
- Sub New()
- Dim fi = New FileInfo(Assembly.GetExecutingAssembly.Location)
- ApplicationName = fi.Name.Replace(fi.Extension, String.Empty)
- AppPath = fi.FullName.Replace(fi.Name, String.Empty)
- 'DataFile = New FileInfo(Path.Combine(AppPath, String.Concat(ApplicationName, ".exe.config.dat")))'weglassen
- Datas = New Dictionary(Of String, Object)()
- End Sub
- Public Overrides Sub Initialize(ByVal name As String, ByVal config As NameValueCollection)
- MyBase.Initialize(ApplicationName, config)
- End Sub
- Public Overrides Property ApplicationName() As String ' hier wird der Produktname von der Assembly angegeben
- Public Overrides ReadOnly Property Name As String
- Get
- Return "UserSettingsProvider"
- End Get
- End Property
- ''' <summary>
- ''' SetPropertyValues wird erst abgearbeitet, wenn ApplicationSettingsBase.Save durchgeführt wird.
- ''' ApplicationSettingsBase stellt sicher, dass für jeden einzelnen Provider nur seine markierten Werte herangenommen werden.
- ''' Egal, ob der Provider auf einer Einzel-Einstellung angesetzt ist oder ob klassenweit die Einstellung angegeben wurde.
- ''' Wenn Einstellungen nicht verändert wurden, müssen sie nicht gespeichert werden!
- ''' Anwendungsspezifische Einstellungen können nicht geändert werden und werden daher auch nicht gespeichert!
- ''' </summary>
- ''' <param name="context"></param>
- ''' <param name="collection"></param>
- Public Overrides Sub SetPropertyValues(ByVal context As SettingsContext, ByVal collection As SettingsPropertyValueCollection)
- For Each prpValue As SettingsPropertyValue In collection
- If Not prpValue.IsDirty OrElse (prpValue.SerializedValue Is Nothing) Then Continue For
- If IsApplicationScoped(prpValue.Property) Then Continue For
- Datas(prpValue.Name) = prpValue.SerializedValue
- Next
- SaveBinary(DataFile, Datas)
- End Sub
- Public Overrides Function GetPropertyValues(ByVal context As SettingsContext, ByVal collection As SettingsPropertyCollection) As SettingsPropertyValueCollection
- SetDataFile()
- If DataFile.Exists Then Datas = LoadBinary(DataFile)
- Dim col As New SettingsPropertyValueCollection()
- For Each prp As SettingsProperty In collection
- Dim Value As New SettingsPropertyValue(prp)
- If Datas.ContainsKey(prp.Name) Then Value = GetPropertyValue(prp) ' Wert von Datas einlesen
- col.Add(Value)
- Next
- Return col
- End Function
- ''' <summary>
- ''' Nur benutzerspezifische Eigenschaften sind zulässig.
- ''' Wenn eine Eigenschaft keinen Wert hat, wird der Defaultwert geladen.
- ''' </summary>
- ''' <param name="prp"></param>
- Private Function GetPropertyValue(ByVal prp As SettingsProperty) As SettingsPropertyValue
- Dim value As New SettingsPropertyValue(prp)
- If IsUserScoped(prp) Then value.SerializedValue = Datas(prp.Name)
- value.IsDirty = False
- Return value
- End Function
- ''' <summary>
- ''' Test auf anwendungsspezifische Eigenschaft
- ''' </summary>
- ''' <param name="prop"></param>
- Private Function IsApplicationScoped(ByVal prop As SettingsProperty) As Boolean
- Return HasSettingScope(prop, GetType(ApplicationScopedSettingAttribute))
- End Function
- ''' <summary>
- ''' Test auf benutzerdefinierte Eigenschaft
- ''' </summary>
- ''' <param name="prop"></param>
- Private Function IsUserScoped(prop As SettingsProperty) As Boolean
- Return HasSettingScope(prop, GetType(UserScopedSettingAttribute))
- End Function
- ''' <summary>
- ''' prüft auf erlaubte Einstellung, so wie es der LocalFileSettingsProvider auch macht ...
- ''' </summary>
- ''' <param name="prop"></param>
- ''' <param name="attributeType"></param>
- Private Function HasSettingScope(ByVal prop As SettingsProperty, ByVal attributeType As Type) As Boolean
- Dim isAppScoped As Boolean = prop.Attributes(GetType(ApplicationScopedSettingAttribute)) IsNot Nothing
- Dim isUserScoped As Boolean = prop.Attributes(GetType(UserScopedSettingAttribute)) IsNot Nothing
- If isUserScoped AndAlso isAppScoped Then Throw New ConfigurationErrorsException("BothScopeAttributes: " & prop.Name)
- If Not isUserScoped AndAlso Not isAppScoped Then Throw New ConfigurationErrorsException("NoScopeAttributes: " & prop.Name)
- Select Case True
- Case attributeType Is GetType(ApplicationScopedSettingAttribute) : Return isAppScoped
- Case attributeType Is GetType(UserScopedSettingAttribute) : Return isUserScoped
- Case Else : Return False
- End Select
- End Function
- ''' <summary>
- ''' Datenfile der gerade aktiven Anwendung bestimmen
- ''' </summary>
- ''' <remarks></remarks>
- Private Sub SetDataFile()
- Dim fi = New FileInfo(Assembly.GetExecutingAssembly.Location)
- AppPath = fi.FullName.Replace(fi.Name, String.Empty)
- DataFile = New FileInfo(Path.Combine(AppPath, String.Concat(ApplicationName, ".exe.config.dat")))
- End Sub
- ''' <summary>
- ''' Daten binär speichern
- ''' </summary>
- ''' <param name="DataFile"></param>
- ''' <param name="Datas"></param>
- Private Sub SaveBinary(DataFile As FileInfo, Datas As Dictionary(Of String, Object))
- SetDataFile()
- ' deleteLocalPathUserSettings()
- Using fs As Stream = File.Create(DataFile.FullName)
- Dim binfmt As New BinaryFormatter()
- binfmt.Serialize(fs, Datas)
- End Using
- End Sub
- ' ''' <summary>
- ' ''' falls der LocalUserAppDataPath vorhanden ist,
- ' ''' wird der Ordner mit allen untergeordneten Verzeichnissen gelöscht
- ' ''' </summary>
- ' ''' <remarks></remarks>
- ' Private Sub deleteLocalPathUserSettings()
- ' Dim di As New DirectoryInfo(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath)
- ' di = di.Parent.Parent.Parent
- ' If di.Exists Then di.Delete(True)
- ' End Sub
- ''' <summary>
- ''' binäre Daten laden
- ''' </summary>
- ''' <param name="DataFile"></param>
- Private Function LoadBinary(DataFile As FileInfo) As Dictionary(Of String, Object)
- SetDataFile()
- Using fs As Stream = File.Open(DataFile.FullName, FileMode.Open)
- Dim binfmt As New BinaryFormatter()
- Return CType(binfmt.Deserialize(fs), Dictionary(Of String, Object))
- End Using
- End Function
- #Region "IApplicationSettingsProvider Members"
- ''' <summary>
- ''' Abrufen der letzten Version der Settingseigenschaft
- ''' </summary>
- ''' <param name="context"></param>
- ''' <param name="property"></param>
- Public Function GetPreviousVersion(ByVal context As SettingsContext, ByVal [property] As SettingsProperty) As SettingsPropertyValue Implements IApplicationSettingsProvider.GetPreviousVersion
- Dim prpValue As New SettingsPropertyValue([property])
- If Datas.ContainsKey([property].Name) Then prpValue.PropertyValue = Datas([property].Name)
- Return prpValue
- End Function
- ''' <summary>
- ''' wieder auf die Defaultwerte der Settings zurücksetzen!
- ''' </summary>
- ''' <param name="context"></param>
- Public Sub Reset(ByVal context As SettingsContext) Implements IApplicationSettingsProvider.Reset
- If DataFile.Exists Then Datas.Clear() : SaveBinary(DataFile, Datas)
- End Sub
- ''' <summary>
- ''' ErfinderDesRades
- ''' fehlende Settings werden sofort der Sammlung entfernt
- ''' neue hinzugekommene Settings werden beim nächsten Speichervorgang gesichert
- ''' </summary>
- ''' <param name="context"></param>
- ''' <param name="properties"></param>
- Public Sub Upgrade(ByVal context As SettingsContext, ByVal properties As SettingsPropertyCollection) Implements IApplicationSettingsProvider.Upgrade
- If Datas.Count = 0 AndAlso DataFile.Exists Then Datas = LoadBinary(DataFile)
- Dim toDelete = Datas.Keys.Except(properties.Cast(Of SettingsProperty).Select(Function(p) p.Name)).ToList
- toDelete.ForEach(AddressOf Datas.Remove)
- End Sub
- #End Region
- End Class
- End Namespace
Die Schnittstelle
IApplicationSettingsProvider
(Versionierung) könnte man weglassen...Dann bleiben die Schnittstellen-Member (
Upgrade
, Reset
und GetPreviousVersion
) bei den Settings ohne Funktion.Dieser Provider wird einfach einem Projekt mitgegeben und ein Verweis angelegt.
Bei der Version DirectorySettingsProvider kann man sogar den Persistierpfad außerhalb des Providers benutzerdefiniert angeben...
Wichtig:
Der Provider wird entweder, wie unten gezeigt, in der Settings.vb den Settings vorgelegt.
Man geht auf die Seite
Menü/Projekt/Projekt-Eigenschaften/Einstellungen
. Beim Anwählen des Menüpunkts Code anzeigen
wird im My-Namespace eine Partial Class des Designercodes erzeugt, in der man dann das Attribut für den UserSettingsProvider angeben kann (der Provider ist dann für alle Settings zuständig)...
Oder man gibt den einzelnen Settings bei der Eigenschaft
Provider
den vollständig qualifizierten Providernamen an!Dann werden nur die extra gekennzeichneten Settings benutzerdefiniert gespeichert - die anderen werden wie üblich persistiert...
Man könnte auch verschiedene Provider, die dem Projekt verwiesen sind, der einzelnen Settings zuordnen.
DemoSolution:
Da werden die Eigenschaften Form.Location und die Form.ClientSize als Settings gebunden.
Zum Weiteren sind noch einige Controls zur Veranschaulichung dargestellt.
Der Pfad zur application.config.dat ist in diesem Projekt im Anwendungspfad festgelegt. Dieser kann individuell angepasst werden...
Diesen Provider kann man sich als Vorlage nehmen und an seine Bedürfnisse anpassen...
Danke an:
@ErfinderDesRades : für seine Vorschläge und Einwände
@RodFromGermany : Hinweis bei Benutzung mehrerer Anwendungen, die den gleichen Provider verwenden
Anbei jetzt die letzte Version der korrigierten DemoSolution.
Dieser Beitrag wurde bereits 27 mal editiert, zuletzt von „VB1963“ ()