Entwickler-Ecke
WinForms - String in Font oder Color konvertieren
Csharp-programmierer - Do 26.11.15 18:32
Titel: String in Font oder Color konvertieren
Hallo ihr Experten.
Da ich die Methode Properties.Settings.Default.Save(); nun wegen dem Debugger nicht mehr nutzen kann, muss ich die Werte für die Variablen Color und Font in einer eigem eigens angelegten Ordner speichern. Wie kann ich nun den Wert für Color/Font per String in einem File speichern? Und wie kann ich diese Werte über den StreamReader in eine Color/Font- Variable umwandeln?
Ralf Jansen - Do 26.11.15 20:25
Zitat: |
Da ich die Methode Properties.Settings.Default.Save(); nun wegen dem Debugger nicht mehr nutzen kann, muss ich die Werte für die Variablen Color und Font in einer eigem eigens angelegten Ordner
speichern. |
Das erklär bitte mal kurz. Ich sehe den Zusammenhang zwischen der Settings Funktion von .Net und dem Debugger nicht :gruebel:
Wenn du aus irgendeinem Grund diese Standardmethode nicht willst dann schreib halt eine eigene Klasse die die Properties hält und benutz einen Serialisierer der eine Instanz der Klasse in ein File serialisieren/deserialisieren kann.
Ein Beispiel für eine Klasse die einen Font und eine Color speichern kann via XmlSerializer
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71:
| public class Settings { private Settings() { }
static Settings() { DefaultPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.ProductName); }
[XmlIgnore] public Color BackGroundColor { get; set; }
[XmlElement("BackGroundColor")] public string SerializeBackGroundColor { get { return ColorTranslator.ToHtml(BackGroundColor); } set { BackGroundColor = System.Drawing.ColorTranslator.FromHtml(value); } }
[XmlIgnore] public Font Font { get; set; }
[XmlElement("Font")] public string SerializeFont { get { if (Font == null) return null;
var converter = TypeDescriptor.GetConverter(typeof(Font)); return converter.ConvertToString(Font); } set { var converter = TypeDescriptor.GetConverter(typeof(Font)); Font = (Font)converter.ConvertFromString(value); } }
[XmlIgnore] public static string DefaultPath { get; set; } public static Settings Load() { if (!File.Exists(Path.Combine(DefaultPath, "Settings.xml"))) return new Settings() { BackGroundColor = SystemColors.Control, Font = Control.DefaultFont };
XmlSerializer serializer = new XmlSerializer(typeof(Settings)); using (var file = File.OpenRead(Path.Combine(DefaultPath, "Settings.xml"))) { return (Settings)serializer.Deserialize(file); } }
public void Save() { XmlSerializer serializer = new XmlSerializer(typeof(Settings)); Directory.CreateDirectory(DefaultPath); using (var writer = new StreamWriter(Path.Combine(DefaultPath, "Settings.xml"), false)) { serializer.Serialize(writer, this); } } } |
Ist eigentlich recht simpel wenn Font/Color serialisierbar wären. ~Einfache~ Dinge wie die Basisdatentypen (int, float, string etc.) wären einfach so serialisierbar ohne spezielle eigene Umwandlung.
Verwendung z.B.
C#-Quelltext
1: 2: 3: 4: 5: 6:
| var settings = Settings.Load();
settings.BackGroundColor = Color.Red; settings.Font = new Font(FontFamily.GenericSansSerif, 8.25f, FontStyle.Regular);
settings.Save(); |
Csharp-programmierer - Do 26.11.15 21:21
Vielen Dank Ralf Jansen.
Ich hätte nur noch zwei Fragen. Wenn ich das Programm zum ersten mal starte, sollen in dem XML-Dokument die Standarteinstellungen geschrieben werden und ab dann kann der Benutzer selbst die Farbeinstellungen speichern. Gibt es noch die Möglichkeit Booleans in der XML-Datei zu speichern?
Und könnten Sie mir den Code bitte ein wenig erklären, damit ich ihn verstehe? Was heißt z.B. typeof(Settings) ?
MFG :)
Ralf Jansen - Do 26.11.15 22:05
Zitat: |
Und könnten Sie mir den Code bitte ein wenig erklären, damit ich ihn verstehe? |
Das Sie ist jetzt Ironie, richtig? ;)
Doku zu
typeof [
https://msdn.microsoft.com/de-de/library/58918ffs.aspx]. typeof gibt dir die Typbeschreibung zu einer Klasse.
Ein System.Type Objekt das beschreibt welche Properties,Methoden, etc. eine Klasse hat. Der hier benutzte XmlSerializer findet darüber hinaus was es aus der Klasse zu serialisieren gibt.
In diesem Fall findet es darin die Properties der Settings Klasse. Die wo das XmlIgnore Attribut dransteht werden ignoriert. Somit bleiben noch SerializeBackGroundColor und SerializeFont über deren Name durch das XmlElement Attribut zu Font und BackGroundColor geändert wird. Somit bekommst du am Ende ein XML mit den Tags Font und BackGroundColor.
Csharp-programmierer - Sa 28.11.15 22:03
Vielen Dank. Das klappt schonmal :).
Aber das Argument bei
return ColorTranslator.ToHtml(BackGroundColor); habe, bezieht sich dies auf
[XmlElement("BackGroundColor)]?
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| [XmlElement("BackGroundColor")] public string SerializeBackGroundColor { get { return ColorTranslator.ToHtml(BackGroundColor); } set { BackGroundColor = System.Drawing.ColorTranslator.FromHtml(value); } } |
Moderiert von
Th69: C#-Tags hinzugefügt
Ralf Jansen - Sa 28.11.15 22:43
Nein so einfach kommt man an Attribute nicht ran. Es ist ein ganz normaler Aufruf der Property.
Die BackGroundColor Property liefert das Color Object das dann über ColorTranslator.ToHtml in der SerializeBackGroundColor in einen string konvertiert wird den man in ein Xml schreiben kann.
Die XmlIrgendwas Attribute sind nur relevant für den XmlSerializer (also ein Klasseniterna der Settings Klasse) für dich als Nutzer der Klasse sind die egal. Werder intern noch extern hast du mit denen zu tun.
Csharp-programmierer - Sa 05.12.15 20:58
Vielen Dank :)
Ich habe den Code nun für mein Projekt optimiert und das ist dabei rausgekommen:
(Form1 Load-Ereignis)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| private void Form1_Load(object sender, EventArgs e) { try { var setings = XML_Datein.Settings.Load(); if (setings.Zumerstenmalgeladen == false) { var r = MessageBox.Show("Darf " + Application.ProductName + "in einem Systemordner auf diesem PC einen Ordner erstellen?\r" + "In diesem Ordner werden alle benötigten Daten und Einstellungen gespeichert." + "Wenn Sie damit einverstanden sind, bestätigen Sie diesen Dialog miz 'Ja'" + "Wenn Sie damit nicht einverstanden sind, bestätigen Sie diesen Dialog mit 'Nein'", "Rechte für " + Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (r == System.Windows.Forms.DialogResult.Yes) { string HauptPfad = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.ProductName); ErstelleOrdner(HauptPfad); setings.Save(); MessageBox.Show("Alle Ordner wurden erfolgreich erstellt. Bitte ändern Sie keine Datein, ansonsten funktioniert diese Anwednung nicht richtig.", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); } } } catch (PathTooLongException) { var d = MessageBox.Show("Der Pfad, welcher eben gerade ausgelesen wurd, ist zu lang. Die Ordner konnten nicht erstellt werden. Soll der Ordner nun als Alternative auf dem Desktop erstellt werden?"); string s = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Application.ProductName); ErstelleOrdner(s); } } |
(Die dazugehörige Funktion)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52:
| private void ErstelleOrdner(string HauptPfad) { var setings = XML_Datein.Settings.Load(); if (!Directory.Exists(HauptPfad)) { Directory.CreateDirectory(HauptPfad); setings.pHauptPfad = HauptPfad; }
string Snippets = Path.Combine(HauptPfad, "Snippets"); if (!Directory.Exists(Snippets)) { Directory.CreateDirectory(Snippets); setings.pSnippets = Snippets; }
string Attribute = Path.Combine(HauptPfad, "Attribute"); if (!Directory.Exists(Attribute)) { Directory.CreateDirectory(Attribute); setings.pAttribute = Attribute; }
string Attribute_HTML = Path.Combine(Attribute, "HTML"); if (!Directory.Exists(Attribute_HTML)) { Directory.CreateDirectory(Attribute_HTML); setings.pAttribute_HTML = Attribute_HTML; }
string Attribute_CSS = Path.Combine(Attribute, "CSS"); if (!Directory.Exists(Attribute_CSS)) { Directory.CreateDirectory(Attribute_CSS); setings.pAttribute_CSS = Attribute_CSS; }
string Tastenkombination = Path.Combine(HauptPfad, "Tastenkombinationen"); if (!Directory.Exists(Tastenkombination)) { Directory.CreateDirectory(Tastenkombination); setings.pTastenkombination = Tastenkombination; }
string Tastenkombination_HTML = Path.Combine(Tastenkombination, "HTML"); if (!Directory.Exists(Tastenkombination_HTML)) { Directory.CreateDirectory(Tastenkombination_HTML); setings.pTako_HTML = Tastenkombination_HTML; } setings.Save(); } |
(Classe zum erstellen der XML-Datein)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140:
| public class Settings { private Settings() { }
static Settings() { DefaultPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Application.ProductName); }
[XmlElement("WordWrap")] public bool WordWrap { get; set; } [XmlElement("SyntaxHighlighting")] public bool SyntaxHighlighting { get; set; } [XmlElement("AutomatischAktualisieren")] public bool AutomatischAktualisieren { get; set; } [XmlElement("ToolStrip")] public bool ToolStrip { get; set; } [XmlElement("Werkzeigleiste")] public bool Werkzeugleiste { get; set; } [XmlElement("Statusstrip")] public bool Statusstrip { get; set; } [XmlElement("ZumErstenMalGeladen")] public bool Zumerstenmalgeladen { get; set; }
[XmlElement("HauptPfad")] public string pHauptPfad { get; set; } [XmlElement("Farbkombination")] public string pFarbkombination { get; set; } [XmlElement("Tags")] public string pTags { get; set; } [XmlElement("Tags-HTML")] public string pTags_HTML { get; set; } [XmlElement("pTags_CSS")] public string pTags_CSS { get; set; } [XmlElement("pTags_JS")] public string pTagsJS { get; set; } [XmlElement("pSnippets")] public string pSnippets { get; set; } [XmlElement("Attribute")] public string pAttribute { get; set; } [XmlElement("Attribute-HTML")] public string pAttribute_HTML { get; set; } [XmlElement("Attribute-CSS")] public string pAttribute_CSS { get; set; } [XmlElement("Tastenkombination")] public string pTastenkombination { get; set; } [XmlElement("TaKo-HTML")] public string pTako_HTML { get; set; } [XmlElement("Tako_CSS")] public string pTako_CSS { get; set; } [XmlElement("Tako_JS")] public string pTako_JS { get; set; } [XmlElement("Projekte")] public string pProjekte { get; set; }
[XmlIgnore] public Color BackGroundColor { get; set; } [XmlElement("BackGroundColor")] public string SerializeBackGroundColor { get { return ColorTranslator.ToHtml(BackGroundColor); } set { BackGroundColor = System.Drawing.ColorTranslator.FromHtml(value); } }
[XmlIgnore] public Color Sekundärfarbe { get; set; }
[XmlElement("Sekundärfarbe")] public string SerializeSekundärfarbe { get { return ColorTranslator.ToHtml(Sekundärfarbe); } set { Sekundärfarbe = System.Drawing.ColorTranslator.FromHtml(value); } }
[XmlIgnore] public Font Font1 { get; set; }
[XmlElement("Font")] public string SerializeFont { get { if (Font1 == null) return null;
var converter = TypeDescriptor.GetConverter(typeof(Font)); return converter.ConvertToString(Font1); } set { var converter = TypeDescriptor.GetConverter(typeof(Font)); Font1 = (Font)converter.ConvertFromString(value); } }
[XmlIgnore] public static string DefaultPath { get; set; }
public static Settings Load() { if (!File.Exists(Path.Combine(DefaultPath, "Settings.xml"))) return new Settings() { BackGroundColor = SystemColors.Control, Font1 = Control.DefaultFont, Sekundärfarbe = SystemColors.ControlDarkDark, Statusstrip = true, Werkzeugleiste = true, WordWrap = true, AutomatischAktualisieren = true, SyntaxHighlighting = true, ToolStrip = true };
XmlSerializer serializer = new XmlSerializer(typeof(Settings)); using (var file = File.OpenRead(Path.Combine(DefaultPath, "Settings.xml"))) { return (Settings)serializer.Deserialize(file); } } public void Save() { XmlSerializer serializer = new XmlSerializer(typeof(Settings)); Directory.CreateDirectory(DefaultPath); using (var writer = new StreamWriter(Path.Combine(DefaultPath, "Settings.xml"), false)) { serializer.Serialize(writer, this); } } |
Ich habe es jetzt nochmal versucht und zwar auf dem Desktop. Die Ordner werden ersellt aber keine XML-Datei. Und auch die MessageBox ploppt immer auf. Also es funktioniert nicht zu 100%.
MFG
Th69 - So 06.12.15 15:03
Dann schau doch mal mit dem Debugger nach...
Ralf Jansen - So 06.12.15 17:08
a.) Was ist der Sinn des Anlegens der ganzen Ordner wenn du die nicht gleich benutzt. Ich würde die Ordner dann anlegen wenn ich sie brauche nicht vorher schonmal leer nur so aus aus verdacht.
b.) In dem dazugehörenden Code sind die ganzen Directory.Exists überflüssig das macht Directory.CreateDirectory schon intern. Da werden nur Ordner angelegt wenn es die noch nicht gibt. Wenn die doch existieren macht CreateDirectory einfach nix.
c.) Wenn die ganzen Unterordner die du in ErstelleOrdner ansprichst immer unterhalb von HauptPfad liegen dann würde ich die gar nicht erst speichern sondern nur die Property einfach von der Settings Klasse berechnen lassen. So wird im Xml dann nur Hauptpfad gespeichert und der Rest eben ~berechnet~. Und in dem Zuge die ganze ErstelleOrdner Methode sterben lassen.
Also z.B. anstatt
C#-Quelltext
1: 2:
| [XmlElement("pSnippets")] public string pSnippets { get; set; } |
einfach
C#-Quelltext
1: 2:
| [XmlIgnore] public string pSnippets { get { return Path.Combine(HauptPfad, "Snippets"); } } |
d.) Das fangen der PathTooLongException verstehe ich nicht. Insbesondere dann wenn man im ExceptionHandler genau das gleiche ausführt was vorher diese Exception ausgelöst hat. Die Wahrscheinlichkeit das das wieder knallt geht irgendwie gegen 100%. Wenn du einen zulangen Pfad verhindern willst mach das sauber im setter der pHauptPfad Property.
e.) Das Naming ist sehr fragwürdig ;) Werde dir klar ob du CamelCasing willst oder Underscore_casing, etwas mit Präfix (so wie die p's an einigen Properties), entscheide dich eindeutig ob du deutsche Bezeichner oder englische möchtest. Es wäre nett wenn du dir irgendeinen Standard ausdenkst und dich daran hältst damit machst du dir und auch anderen das Leben leichter.
f.) Standardmäßig auf dem Desktop speichern ist eher ungewöhnlich.
Zu deinem Problem. Von welcher MessageBox sprichst du. Und wenn du sonstige Fehlermeldungen bekommst solltest du die uns auch benennen.
Csharp-programmierer - So 06.12.15 18:22
Ralf Jansen Ich brauche den Bool ZumErstenMalGelden, damit eine MessageBox (welche fragt, ob die Anwendung Ordner erstellen darf) nur beim ersten Start der Anwendung ausgegeben wird. Und damit werden schonmal alle Ordner erstellt, welche das Programm benötigt.
Zitat: |
Das Naming ist sehr fragwürdig ;) Werde dir klar ob du CamelCasing willst oder Underscore_casing, etwas mit Präfix (so wie die p's an einigen Properties), entscheide dich eindeutig ob du deutsche Bezeichner oder englische möchtest. Es wäre nett wenn du dir irgendeinen Standard ausdenkst und dich daran hältst damit machst du dir und auch anderen das Leben leichter. |
Was meinst
Du :lol: mit CamelCasting und Underscore-casting? Und bei mir steht das p immer für Pfad :o
Zitat: |
Das fangen der PathTooLongException verstehe ich nicht. Insbesondere dann wenn man im ExceptionHandler genau das gleiche ausführt was vorher diese Exception ausgelöst hat. Die Wahrscheinlichkeit das das wieder knallt geht irgendwie gegen 100%. Wenn du einen zulangen Pfad verhindern willst mach das sauber im setter der pHauptPfad Property. |
Ich habe erst die Ordner in die ApplicationData gespeichert, doch als Test auf den Desktop. Beim Einfügen des Codes in diesem Thread habe ich vergessen dies wieder einzuprogrammieren. Und in dem ExcaptionHandling werden dann die Ordner auf dem Desktop erstellt :?
Zitat: |
In dem dazugehörenden Code sind die ganzen Directory.Exists überflüssig das macht Directory.CreateDirectory schon intern. Da werden nur Ordner angelegt wenn es die noch nicht gibt. Wenn die doch existieren macht CreateDirectory einfach nix. |
Das wusste ich noch nicht. Jetzt werden ich den Code aber kürzen 8)
Ralf Jansen - So 06.12.15 18:43
Zitat: |
Was meinst Du :lol: mit CamelCasting und Underscore-casting? Und bei mir steht das p immer für Pfad :o |
Wenn es Pfad bedeutet dann schreib doch Pfad hin. Buchstaben sparen hilft nicht insbesondere wenn du dir bewusst machst das auch andere deinen Code lesen.
Bei den Dingen die ich da ansprach geht es darum wie man sinnvoll Bezeichner zusammensetzt. Ein sinnvoller Bezeichner besteht ja oft aus mehreren Teilen und muss dann lesbar zusammengesetzt werden. Da gibt es halt verschiedene Methoden Beispiele für den Bezeichner "mein lieber Bezeichner"
Quelltext
1: 2: 3:
| Pascal case - MeinLieberBezeichner Camel case - meinLieberBezeichner Underscore - mein_lieber_Bezeichner |
Bei dir gibt es jede dieser Varianten. Üblich wäre Camel case für Klasseninterna (internal, private) und Pascal case für öffentliches (public, proteced). Underscores sind allgemein eher verpönt.
Genauso wie Präfixe mit Sonderbedeutungen. Früher wurde sowas oft in diversen Sprachen als Typ Indikator benutzt (i-integer, s-string etc.) das ist auch mittlerweile verpönt hat mich aber deinem p gleich auf die falsche Fährte geschickt ;)
Csharp-programmierer - Di 08.12.15 17:13
Das Problem mit dem Boolean: Der Wert muss bei Start des Programms false sein. Und ab da immer true, damit die MessageBox nicht bei jedem Programmstart angezeigt wird. Woran kann es liegen?
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| private void Form1_Load(object sender, EventArgs e) { var setings = XML_Datein.Settings.Load(); if (setings.Zumerstenmalgeladen == false) { var r = MessageBox.Show("Darf " + Application.ProductName + "in einem Systemordner auf diesem PC einen Ordner erstellen?\r" + "In diesem Ordner werden alle benötigten Daten und Einstellungen gespeichert." + "Wenn Sie damit einverstanden sind, bestätigen Sie diesen Dialog miz 'Ja'" + "Wenn Sie damit nicht einverstanden sind, bestätigen Sie diesen Dialog mit 'Nein'", "Rechte für " + Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (r == System.Windows.Forms.DialogResult.Yes) { string HauptPfad = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Application.ProductName); ErstelleOrdner(HauptPfad); setings.Zumerstenmalgeladen = true; MessageBox.Show("Alle Ordner wurden erfolgreich erstellt. Bitte ändern Sie keine Datein, ansonsten funktioniert diese Anwednung nicht richtig.", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); } setings.Save(); } } |
Ralf Jansen - Di 08.12.15 19:31
Hast du deen im mal in Die XML Datei reingeschaut was da drin steht nach dem Aufruf von save()?
Csharp-programmierer - Di 08.12.15 20:14
Das Problem ist, ich kann die XML- Datei nirgendwo finden. Auf dem Desktop unter den defaultPfad ist nichts.
Ralf Jansen - Di 08.12.15 20:40
Ich habe deine Settings gerade mal probiert
C#-Quelltext
1: 2: 3: 4: 5: 6:
| var settings = Settings.Load(); if (!settings.Zumerstenmalgeladen) { settings.Zumerstenmalgeladen = true; } settings.Save(); |
und das funktioniert wie erwartet. Irgendwas im Code drumherum machst du vermutlich was falsch. Was da falsch läuft solltest du durch debuggen raus finden können. Jedenfalls viel einfacher als wir das durch Ferndiagnose können.
Csharp-programmierer - Di 08.12.15 21:11
Es funktioniert nicht.
Speichern-Funktion:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| public void Save() { XmlSerializer serializer = new XmlSerializer(typeof(Settings)); Directory.CreateDirectory(DefaultPath); using (var writer = new StreamWriter(Path.Combine(DefaultPath, "Settings.xml"), false)) { serializer.Serialize(writer, this); } } |
FormLoad-Ereignis:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| private void Form1_Load(object sender, EventArgs e) { var setings = XML_Datein.Settings.Load(); if (setings.Zumerstenmalgeladen == false) { setings.Zumerstenmalgeladen = true; var r = MessageBox.Show("Darf " + Application.ProductName + "in einem Systemordner auf diesem PC einen Ordner erstellen?\r" + "In diesem Ordner werden alle benötigten Daten und Einstellungen gespeichert." + "Wenn Sie damit einverstanden sind, bestätigen Sie diesen Dialog miz 'Ja'" + "Wenn Sie damit nicht einverstanden sind, bestätigen Sie diesen Dialog mit 'Nein'", "Rechte für " + Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (r == System.Windows.Forms.DialogResult.Yes) { string HauptPfad = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Application.ProductName); ErstelleOrdner(HauptPfad); setings.Zumerstenmalgeladen = true; MessageBox.Show("Alle Ordner wurden erfolgreich erstellt. Bitte ändern Sie keine Datein, ansonsten funktioniert diese Anwednung nicht richtig.", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); } setings.Save(); } } |
Die XML- Datei wird immer noch nicht erstellt :(
Ralf Jansen - Di 08.12.15 21:46
Ich kann nur wiederholen du musst lernen zu debuggen. Step durch deinen Code und schau was passiert.
Csharp-programmierer - Mi 09.12.15 16:50
Ok. Vielen Dank :)
Ich habe es jetzt nochmal ausgeführt und der Debugger hat ausgegenen, dass die Ausnahme System.InvalidOperationException, welche ich nach dem 2. Start abgefangen habe und dieser Inhalt kam raus:
Auf "DieAnwendung.XML_Datein" kann aufgrund der Sicherheitsebene nicht zugegriffen werden. Nur öffentliche Typen können verarbeitet werden.
So weit so gut :D. Und was heißt das jetzt auf deutsch?
Ralf Jansen - Mi 09.12.15 17:12
Zitat: |
"DieAnwendung.XML_Datein" |
Was ist das denn? Vom Code hätte ich gedacht XML_Datein ist ein Namespace da macht dann die Fehlermeldung aber keinen Sinn.
Csharp-programmierer - Mi 09.12.15 17:30
Der Namespace ist: Web_Studio
Und die Klasse der XML- Datein: XML_Datein
Ich habe die Klasse, die die Speichern- Funktion beinhaltet, in der KLasse XML_Datein
Th69 - Mi 09.12.15 17:43
Und Settings ist dann eine Unterklasse dieser Hauptklasse?
Dann muß diese für die Serialisierung (anscheinend) auch public sein.
Aber warum packst du die Settings-Klasse nicht in einen eigenen Namensbereich (und in eine eigene Datei)?
PS: u.a. wegen den komischen (übersetzten) Fehlermeldungen benutze ich das VS nur auf englisch (auch im Web findet man bei den englischen Fehlermeldungen mehr und bessere Lösungen).
PPS: Es heißt Dateien.
Csharp-programmierer - Mi 09.12.15 18:33
Vielen Dank. Jetzt haut es hin und die XML- Datei wird erstellt, obwohl ich nicht so genau weiß, warum die Klasse public gemacht werden muss.
Vielen Dank =)
Ralf Jansen - Mi 09.12.15 18:35
Weil der XmlSerializer nur das Serialisieren kann wo er auch rann kommt und wenn die Klasse private oder internal ist kann der die nicht sehen.
Csharp-programmierer - Mi 09.12.15 20:48
Ich habe jetzt nur noch ein Problem :oops:
Ich muss ja für die Laufzeit des Programms neue Objekte (RichTextBox, TabPage) erstellen, für die ich die Werte in der Klasse Settings brauche. Ich habe verucht im Namespace diese Klasse zu instanzieren:
C#-Quelltext
1:
| var settings = XML-Datein.Settings.Load(); |
Jedoch kennt er var da nicht :nixweiss:
Aber ich kann ja jetzt nicht in jeder kleinen Funktion die Load- Funktion ausführen. Das ist doch quatsch, oder?
Ralf Jansen - Mi 09.12.15 20:56
Zitat: |
Ich habe verucht im Namespace diese Klasse zu instanzieren: |
Code steckt immer in Methoden und Methoden gehören zu Klassen.
Zitat: |
Aber ich kann ja jetzt nicht in jeder kleinen Funktion die Load- Funktion ausführen. Das ist doch quatsch, oder? |
Mach aus settings eine Klassenvariable und rufe Load am Anfang einfach einmal auf. Auf settings kannst du dann von überall in der Klasse/Form aus auf zugreifen.
Wenn du aus mehreren Klassen/Formen auf Settings zugreifen willst implementiere in der Settings Klasse eine Singleton Instanz von Settings.
Csharp-programmierer - Mi 09.12.15 21:06
Und wie deklariere ich eine Klassemvariable?
Ralf Jansen - Mi 09.12.15 21:31
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| public partial class MeinLiebeForm : Form { Settings settings = null; public MeinLiebeForm() { InitializeComponent();
settings = Settings.Load(); }
private void button1_Click(object sender, EventArgs e) { if (!settings.Zumerstenmalgeladen) { } } } |
Csharp-programmierer - Mi 09.12.15 21:47
Ich habe die Klassenvariable jetzt so deklariert: MaiLet_Webstudio_2015.XML_Datein.Settings settings = null;.
Das haut jetzt auch endlich hin. Das Programm heißt bei VS nur so (also MaiLet_Webstudio_2015). Wenn ich es jetzt unter einem anderen Namen veröffentlichen will, verfällt dann praktisch dieser Name und das Programm funktioniert nicht?
Ralf Jansen - Do 10.12.15 11:53
Wie das Programm nachher heißt hat nix mit den intern benutzten Namespace Namen zu tun. Die sind zu Anfang wenn du ein Projekttemplate ausführst gleich muß aber nicht so sein und kannst die belibieg in den Projekteinstellungen ändern.
Csharp-programmierer - Do 10.12.15 17:15
Okay, vielen Dank.
Jetzt habe ich gerade germerkt, dass die XML- Datei gar nicht die ganzen Pfade beinhaltet. Wenn ich den Quellcode richtig verstanden habe, wird der Code ausgeführt, wenn die XML- Datei nicht existiert:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| public static Settings Load() { if (!File.Exists(Path.Combine(DefaultPath, "Settings.xml"))) return new Settings() { BackGroundColor = Color.White, Font1 = new Font(SystemFonts.DefaultFont, FontStyle.Regular), Sekundärfarbe = Color.Black, Statusstrip = true, Werkzeugleiste = true, WordWrap = true, AutomatischAktualisieren = true, SyntaxHighlighting = true, ToolStrip = true };
XmlSerializer serializer = new XmlSerializer(typeof(Settings)); using (var file = File.OpenRead(Path.Combine(DefaultPath, "Settings.xml"))) { return (Settings)serializer.Deserialize(file); } } |
Obwohl ich nun auf meinem Desktop in dem Programmordner die Datei finde :?: :?:
Ralf Jansen - Do 10.12.15 23:55
Zitat: |
Wenn ich den Quellcode richtig verstanden habe, wird der Code ausgeführt, wenn die XML- Datei nicht existiert: |
Wenn nicht gefunden bekommst du ein Object mit den im Code gesetzten Defaults oder die Datei wird gelesen (halt wenn sie existiert).
Zitat: |
Obwohl ich nun auf meinem Desktop in dem Programmordner die Datei finde :?: :?: |
Die Bemerkung verstehe ich nicht.
Csharp-programmierer - Fr 11.12.15 16:32
Das Programm ertsllt auf dem Desktop einen Ordner, in dem alle Unterorder erhalten sind, die das Programm benptigt:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| [XmlElement("HauptPfad")] public string pHauptPfad { get; set; } [XmlElement("Farbkombination")] public string pFarbkombination { get; set; } [XmlElement("Tags")] public string pTags { get; set; } [XmlElement("Tags-HTML")] public string pTags_HTML { get; set; } [XmlElement("pTags_CSS")] public string pTags_CSS { get; set; } [XmlElement("pTags_JS")] public string pTagsJS { get; set; } |
Das sollen die Pfade der Ordner gespeichert werden. Und ich diesem Ordner, der vom Programm auf dem Desktop erstellt wurde, befindet sich auch die Settings-XML-Datei. Aber anscheindend wird der Code ausgeführt, wenn die XML-Datei nicht gefunden wurde, obwohl sie existiert.
EDIT: Ich habe nun anhand des Debuggerprotokolls erkannt, dann in dem Form-Load-Event eine NullReferenceExeption aufgetreten ist, welche ich durch eine MessageBox abgefangen habe. Ich habe nun
settings = MaiLet_Webstudio_2015.XML_Datein.Settings.Load(); in den Konstruktor eingebunden und somit den Fehler behoben. Am Debuggerprotokoll kann ich nun keinen Fehler mehr entdecken, jedoch wird die XML-Datei mit den ganzen Booleans erstellt, die Pfade fehlen dort jedoch noch :roll:
Außerdem stand in diesem Protokoll noch: PDB-Datei wurde nicht gefunden oder konnte nicht geöffnet werden.
Moderiert von
Th69: Beitragsformatierung überarbeitet.
Csharp-programmierer - Do 17.12.15 15:56
Hallo meine Lieben. Ich habe den Fehler nun erkannt. Er war mal wieder typisch für mich :autsch:
Ich habe in der OrdnerLaden- Funktion eine Extra Klassenvariable benutzt. Ich habe sie nun durch die Hauptklassenvariable ausgetauscht und schon funktioniert die Anwendung wieder.
MFG für die super Hilfe :)
Csharp-programmierer - Sa 19.12.15 23:04
Nur noch eine kleine Nebenfrage. Ich habe die Klassenvariable der Mainform nun statisch gemacht, damit ich von allen Formen problemlos darauf zugreifen kann. Was meint ihr? Ist das so gut oder nicht?
Th69 - So 20.12.15 10:51
Das ist überhaupt nicht gut, da untergeordnete Forms keinen Zugriff auf übergeordnete (Haupt-)Forms haben sollten.
Pack die Variable (wenn es überhaupt eine statische sein muß) besser in eine eigene unabhängige Klasse - alternativ könntest du dafür die
Settings-Klasse des WinForms-Projekt benutzen (Zugriff darauf dann per
Properties.Settings.Default).
Oder so wie Ralf schon geschrieben hat:
Ralf Jansen hat folgendes geschrieben: |
Wenn du aus mehreren Klassen/Formen auf Settings zugreifen willst implementiere in der Settings Klasse eine Singleton Instanz von Settings. |
Csharp-programmierer - So 20.12.15 20:26
Okay. Und wenn ich diese Klassenvariable nun auf
protected setzt und die einzelnen Klassen dann davon erben?
Da mir eine extra Klasse für diese Variable übertrieben erscheint. Und wie man eine Klasse implentiert, weiß ich nicht. Was halten Sie von dem
protected?
C#-Quelltext
1:
| public partial class Form2 : Form1 |
Ralf Jansen - So 20.12.15 20:58
Zitat: |
Da mir eine extra Klasse für diese Variable übertrieben erscheint |
Du hast die Klasse wo das hingehört bereits ;) Ansonsten Klassen fressen kein Brot da muss man nicht zwanghaft sparen. Eine sinnlose Vererbung ist da viel problematischer. Faustformel die meisten Dinge lassen sich durch Klassenbeziehung besser lösen als durch Vererbung. Vererbung also vorsichtig einsetzen.
Du hast ja am Anfang die Standardklasse vom Framework benutzt. Hast du dich mal gefragt wenn du dort sowas aufrufst wie
Settings.Default.Save() was das Default an der Settings Klasse soll?
Gib deiner Settings Klasse einfach eine passende Property um an eine einzelne (ein Singleton) Instanz zu kommen. Wenn du nicht möchtest das man anders als über die Default Property an die Settings kommt könntest du jetzt die Load Methode auf private setzen. Dann hast du einen echten Singleton gebaut.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| private static Settings defaultInstance; public static Settings Default { get { if (defaultInstance == null) defaultInstance = Settings.Load(); return defaultInstance; } } |
Csharp-programmierer - So 20.12.15 22:33
Wenn ich nun ihren Code eingebe, dann wird mir defaultInstance rot unterstrichen und als Fehler steht: Für das nicht statische Feld ist ein Objektverweis erforderlich.
Könnten Sie mir bitte noch erklären, was ein Singleton ist?
Ralf Jansen - So 20.12.15 22:59
Die Variable muss statisch sein das habe ich vergessen. Sorry. Im Code korrigiert.
Zitat: |
Könnten Sie mir bitte noch erklären, was ein Singleton ist? |
a.) Erst nachdem du es ergoogelt hast und es dir dann noch nichts sagt und b.) du es dann mit dem du weiter probierst.
Csharp-programmierer - So 20.12.15 23:21
Also den Singelton rufe ich nun so auf: Settings.Default.pSnippets
Wie ich es jetzt verstanden habe, nimmt man ein Singelton, wenn man ein Objekt nur einmal instanzieren möchte, aber trotzdem von allen Objekten darauf zugreifen will, oder?
Ralf Jansen - So 20.12.15 23:35
Zitat: |
Wie ich es jetzt verstanden habe, nimmt man ein Singelton, wenn man ein Objekt nur einmal instanzieren möchte, aber trotzdem von allen Objekten darauf zugreifen will, oder? |
So stehts auch ungefähr im Wiki, ja ;)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!