Benutzereinstellungen sinnvoll speichern

  • VB.NET
  • .NET (FX) 4.0

Es gibt 38 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    sonne75 schrieb:

    Man kann sich nicht immer (im Berufsleben) aussuchen, welche Treiber man benutzt...


    Wem sagst du das...

    Um zu der Klasse von @ErfinderDesRades zurückzukommen:
    Ich verstehe das ganze im Prinzip. Hab diese auch nun in einem Testprojekt ohne Probleme zum Laufen gebracht.
    Was ich nicht verstehe, wie eine einfache IList(of String) weiß welcher Einstellung welchem Control zugeordnet ist. Ich denke wenn ich diesen Funken verstanden habe, könnt ich dies für mein Projekt verwenden.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    hier eine bisserl verbesserte version (vbCodeProvider ist oversized, die TypeConverter rufe ich besser von TypeDescriptor ab) - mit Erklärungen: ComplexConverter auf VBP

    Was du nicht verstehst ist grad der Witz an der Sache: Lese-Code und Schreib-Code ist derselbe. Wenn du also erst Button1.Text schreibst, und danach dann Checkbox2.Checked, dann wird auch in genau dieser Reihenfolge gelesen. Geht nicht anners - denn es ist derselbe Code!
    Die dumme IList(Of String) weiß es tatsächlich nicht, es ist der EventhandlerCode selbst, der es weiß. :D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ich habe jetzt das Ganze angeschaut, aber es greift doch auf My.Settings zurück und hat mit Vorgaben von @fichz (eine DB-Tabelle mit Spalten) nichts zu tun? Oder ist damit gemeint, dass dieser String einfach statt in My.Settings einfach in eine Tabellenspalte geschrieben wird?
    Aber wird damit nicht geschummelt, wenn die Aufgabenstellung für @fichz eine DB-Lösung war?
    Wie gesagt, dafür müsste ich die Aufgabenstellung von ihm kennen, und wie genau sie eingehalten werden muss. Denn mit einer DB-Tabelle hat das Ganze ja recht wenig zu tun (außer, dass der String da reingeschrieben wird).
    Muss er entscheiden, ob es als Lösung gilt.

    fichz schrieb:

    ich habe eine eher generelle Frage zum Speichern von Benutzereinstellungen. Ich will diese in einer SQL-Server Datenbank hinterlegen.
    also da nehme ich an, die DB beschäftigt sich vorwiegend mit anneren Sachen, aber es gibt auch eine Tabelle User, und wenn man den User um eine Spalte "GuiSettings" (String) erweitert, dann kriegt jeder User sein Form in genau dem Zustand hingeflackt, in dem er es verlassen hat (hab ich grad letzte Woche so verbaut).
    Wenn ich diese Klasse nun richtig verstanden habe, dann muss jedoch die Reihenfolge des Strings immer gleich bleiben oder?

    Ich werde mir diese Methode anhand eines Testprojekts zu Gemüte führen, hab jedoch nun auch eine andere Idee wie es eventuell per XML gehen könnte. Werde beides mal versuchen und anschließend berichten.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    du kannst es nicht fassen, was? ;)
    Die Reihenfolge bleibt immer gleich, das ist unausweichlich. Es ist derselbe Code, der liest und schreibt. Wie soll sich da jemals die Reihenfolge ändern können?
    Die Reihenfolge kann sich nur ändern, wenn du den lese/schreib - Code zwischenzeitlich änderst, etwa statt des Treeviews nun ein Datagridview persistierst.
    Also das Programm neu kompiliert hast, mit Änderungen am Persistenz-Code.
    Und auch das hat keine annere Auswirkung, als dass dann - dank des Rollbacks - wieder bei den Default-Werten angefangen wird.
    Die Reihenfolge bleibt dann gleich wenn ich sie gleiche belasse ja ;)
    Ich denke hier eher an "Die eine Checkbox wird nicht mehr gebraucht -> weg damit" Im "Gesamtstring" ist der "True" Wert jedoch an dritter Stelle gewesen.
    Somit könnte ich den gespeicherten String nicht wieder herstellen. Wenn ich, wie gesagt, das korrekt verstanden habe.

    Ok jetzt weiß ich was du meinst. Da das Backup (was vorher passiert) erstellt wird und im Fehlerfall dann eingetragen wird ist es egal wenn sich sowas in der Art ändert.
    Beim nächsten speichern wird der String wieder korrekt geschrieben und kann beim nächsten Start dann wieder korrekt restauriert werden.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    So ich mach es nun doch nicht mit dem ComplexConverter sondern habe mir nun was ähnliches gebastelt.
    Das ganze läuft nun über XML und Serialisierung (Hinweis war von @ThuCommix -> ComplexConverter: alles in einen String und zurück).

    Ich erstelle mir nun für jede Form eine eigene Settingsklasse welche serialisierbar ist. Dieser geb ich beim Schließen der Form die Einstellungen welche halt für diese Form so passen.
    Die Klasse wird dann mit XML serialisiert und der ganze XML-String was dabei zustande kommt wird dann in die Datenbank gespeichert (ID, BedienerID, Formname, Daten).

    Beim erneuten Start wird versucht diese Klasse wiederherzustellen und die Settings dann wieder zu setzen.

    Warum mach ich das nun so?

    Das hat eigentlich mehrere Gründe:
    • Irgendwie stoßt mir das ungut auf, dass es alles Strings sind. Hab ich das in einer Klasse hab ich gezielt die Datentypen die ich benötige
    • Ich hab teilweise kompliziert generierte Settings zu speichern. Als Beipsiel ein Datengrid welches Expander beinhaltet wo der "Expanded-Status" mitgesichert wird (Dieses Grid ist jedoch an keine DataSource gebunden)
    • Ich hab einige Tests gemacht wenn ich die Klasse verändere. Darunter Eigenschaften entfernen, Eigenschaftsnamen ändern, Datentypen ändern. Das Ergebnis: Es wird keine Exception geworfen sondern einfach die Sachen die gar nicht mehr passen ignoriert.
    ​lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    wie du wolle :/
    nur hast du jetzt ebenfalls strings, und ein vielfaches an Code, weil du für jedes Form eine Extra-Klasse basteln musst, und recht komplizierten Code, um die Extra-Klasse zu befüllen und auszulesen und anzuwenden.
    Und zur Komplexität: thuCommix tönt ja, Serialisierung sei iwie besser, oder zumindest gleichwertig (ohne es zu belegen). Aber versuch mal wirklich die im Tut gegebene Persistenz mit deinem Ansatz umzusetzen - bin ich gespannt, ob du das schaffst, und wie das dann aussieht.
    Also wenn du von "kompliziert" reden willst.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Das stimmt. Ich bin aber generell lieber der Typ der etwas mehr Code schreibt, um das ganze dann halt besser lesbar/verständlicher zu machen und man auch problemlos erweitern kann. Von dem her ist mir diese Möglichkeit lieber.
    Und zum Speichern + Auslesen sind leider die Settings so verschieden, dass ich das fast nicht verallgemeinern kann. Deswegen leg ich lieber in jeder Form selbst Hand an. :)

    Trotzdem danke für die Tipps! Nun hab ich (zumindest für mich) ein System welches sehr flexibel Benutzer-Daten speichern kann :)

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten

    fichz schrieb:

    Und zum Speichern + Auslesen sind leider die Settings so verschieden, dass ich das fast nicht verallgemeinern kann.
    Was ist verschieden? Bei mir ists ein String, bei sinds 4 Strings (ID, BedienerID, Formname, Daten).
    Da mein Sample nur einen Bediener und nur 1 Form hat, und die ID Datenbank-Sache ist, entfallen ID, BedienerID, Formname.
    Also soo verschieden finde ich das nicht.
    Nein nein. Es nicht verschieden. Sogar sehr ähnlich. Nur verwende ich halt ein XML und du einen mit Seperator getrennten String.
    Gefühlsmäßig gefällt mir die XML Variante halt mehr. Wobei ich nicht sage, dass deine Methode schlecht ist :)

    Ist rein persönlicher Natur.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Hier auch noch mal zur Vollständigkeit ein XML-Ansatz zum serialisieren von Controls:

    Die Klasse "ControlSerializer":
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Drawing;
    4. using System.IO;
    5. using System.Windows.Forms;
    6. using System.Xml.Serialization;
    7. public class ControlSerializer
    8. {
    9. private Control _control;
    10. private List<MyControlProp> _props = new List<MyControlProp>();
    11. private List<MyControlProp> Props
    12. {
    13. get { return _props; }
    14. set { _props = value; }
    15. }
    16. public Control Control
    17. {
    18. get { return _control; }
    19. set { _control = value; }
    20. }
    21. public ControlSerializer(Control ctrl)
    22. {
    23. this.Control = ctrl;
    24. }
    25. public void Serialize(string filePath)
    26. {
    27. Serialize(this.Control, filePath);
    28. }
    29. public void Serialize(Control ctrl, string filePath)
    30. {
    31. if (ctrl != null)
    32. {
    33. this.Props.Clear();
    34. ReadPropes(ctrl);
    35. XmlSerializer serializer = new XmlSerializer(typeof(List<MyControlProp>));
    36. using (FileStream stream = new FileStream(filePath, FileMode.Create))
    37. serializer.Serialize(stream, this.Props);
    38. }
    39. else
    40. {
    41. throw new Exception();
    42. }
    43. }
    44. public void Deserialize(string filePath)
    45. {
    46. Deserialize(this.Control, filePath);
    47. }
    48. public void Deserialize(Control ctrl, string filePath)
    49. {
    50. if (ctrl != null)
    51. {
    52. XmlSerializer serializer = new XmlSerializer(typeof(List<MyControlProp>));
    53. using (FileStream stream = new FileStream(filePath, FileMode.Open))
    54. {
    55. object obj = serializer.Deserialize(stream);
    56. this.Props = (List<MyControlProp>)obj;
    57. WritePropes(ctrl);
    58. }
    59. }
    60. else
    61. {
    62. throw new Exception();
    63. }
    64. }
    65. private void WritePropes(Control ctrl)
    66. {
    67. foreach (MyControlProp item in this.Props)
    68. {
    69. Control[] chCtrllist = ctrl.Controls.Find(item.Name, true);
    70. if (chCtrllist.Length > 0)
    71. item.SetControlValues(chCtrllist[0]);
    72. }
    73. }
    74. private void ReadPropes(Control ctrl)
    75. {
    76. MyControlProp prop = new MyControlProp(ctrl);
    77. this.Props.Add(prop);
    78. if (ctrl.HasChildren)
    79. {
    80. foreach (Control item in ctrl.Controls)
    81. ReadPropes(item);
    82. }
    83. }
    84. [Serializable]
    85. public class MyControlProp
    86. {
    87. private string _name;
    88. private string _text;
    89. private int _selectedIndex;
    90. private bool _disbaled;
    91. private bool _visible;
    92. private Color _foreColor;
    93. private Color _backColor;
    94. private bool _checked;
    95. private int _checkState;
    96. public int CheckState
    97. {
    98. get { return _checkState; }
    99. set { _checkState = value; }
    100. }
    101. public bool Checked
    102. {
    103. get { return _checked; }
    104. set { _checked = value; }
    105. }
    106. public string Name
    107. {
    108. get { return _name; }
    109. set { _name = value; }
    110. }
    111. public string Text
    112. {
    113. get { return _text; }
    114. set { _text = value; }
    115. }
    116. public int SelectedIndex
    117. {
    118. get { return _selectedIndex; }
    119. set { _selectedIndex = value; }
    120. }
    121. public bool Disbaled
    122. {
    123. get { return _disbaled; }
    124. set { _disbaled = value; }
    125. }
    126. public bool Visible
    127. {
    128. get { return _visible; }
    129. set { _visible = value; }
    130. }
    131. public Color ForeColor
    132. {
    133. get { return _foreColor; }
    134. set { _foreColor = value; }
    135. }
    136. public Color BackColor
    137. {
    138. get { return _backColor; }
    139. set { _backColor = value; }
    140. }
    141. /// <summary>
    142. /// Parameterless ctr is required to make
    143. /// class serializable
    144. /// </summary>
    145. public MyControlProp()
    146. {
    147. }
    148. /// <summary>
    149. ///
    150. /// </summary>
    151. /// <param name="ctrl"></param>
    152. public MyControlProp(Control ctrl)
    153. {
    154. GetControlValues(ctrl);
    155. }
    156. /// <summary>
    157. /// Method to read control values and assign it to object
    158. /// </summary>
    159. /// <param name="ctrl"></param>
    160. public void GetControlValues(Control ctrl)
    161. {
    162. if (ctrl == null)
    163. throw new Exception("UnhandledException");
    164. this.Name = ctrl.Name;
    165. this.Text = ctrl.Text;
    166. this.Disbaled = ctrl.Enabled;
    167. this.Visible = ctrl.Visible;
    168. this.ForeColor = ctrl.ForeColor;
    169. this.BackColor = ctrl.BackColor;
    170. if (ctrl.GetType() == typeof(ComboBox) || ctrl.GetType() == typeof(ListBox))
    171. {
    172. ListControl lst = (ListControl)ctrl;
    173. this.SelectedIndex = lst.SelectedIndex;
    174. }
    175. else if (ctrl.GetType() == typeof(CheckBox))
    176. {
    177. CheckBox ch = (CheckBox)ctrl;
    178. this.Checked = ch.Checked;
    179. this.CheckState = (int)ch.CheckState;
    180. }
    181. else if (ctrl.GetType() == typeof(RadioButton))
    182. {
    183. RadioButton btn = (RadioButton)ctrl;
    184. this.Checked = btn.Checked;
    185. }
    186. }
    187. /// <summary>
    188. /// Method to set values to controls
    189. /// </summary>
    190. /// <param name="ctrl"></param>
    191. public void SetControlValues(Control ctrl)
    192. {
    193. if (ctrl == null)
    194. throw new Exception("UnhandledException");
    195. ctrl.Text = this.Text;
    196. ctrl.Enabled = this.Disbaled;
    197. ctrl.Visible = this.Visible;
    198. ctrl.ForeColor = this.ForeColor;
    199. ctrl.BackColor = this.BackColor;
    200. if (ctrl.GetType() == typeof(ComboBox) || ctrl.GetType() == typeof(ListBox))
    201. {
    202. ListControl lst = (ListControl)ctrl;
    203. lst.SelectedIndex = this.SelectedIndex;
    204. }
    205. else if (ctrl.GetType() == typeof(CheckBox))
    206. {
    207. CheckBox ch = (CheckBox)ctrl;
    208. ch.Checked = this.Checked;
    209. ch.CheckState = (CheckState)this.CheckState;
    210. }
    211. else if (ctrl.GetType() == typeof(RadioButton))
    212. {
    213. RadioButton btn = (RadioButton)ctrl;
    214. btn.Checked = this.Checked;
    215. }
    216. }
    217. }
    218. }


    Aufruf zum Speichern einer ganzen Form mit allen Controls:

    C#-Quellcode

    1. ControlSerializer serializer = new ControlSerializer(this);
    2. serializer.Serialize(@"D:\test.xml");

    Und wieder zurück:

    C#-Quellcode

    1. if (File.Exists(@"D:\test.xml"))
    2. {
    3. ControlSerializer serializer = new ControlSerializer(this);
    4. serializer.Deserialize(@"D:\test.xml");
    5. }

    Das sind jetzt über 250 Zeilen, aber etwa SplitterDistance eines SplitContainers, mit der der User sich grad die linke oder rechte Seite für ihn richtig eingestellt hat, kannst du damit nicht persistieren.

    auch bezweifel ich, dass das die Write-Methode auch Controls findet und restauriert, die auf einem Panel liegen, oder gar in einem eingebunden komplexen UserControl - hast du das getestet?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()