Inhalt von vielen Text- und Button-Boxen in XML-Datei speichern, wie am Besten ?
-
Hi Leute
Ich bin totaler Programmieranfänger und hab mich direkt mal an Visual-C# mit ner GUI rangewagt ... klappt auch mehr oder weniger gut, dauert halt enorm lange bis man erfolge sieht, aber es geht soweit. "Learning by doing" halt ...
Wie bereits beschrieben, habe ich eine GUI (Form) mit vielen Text und Button-Objekten drauf.
Per Knopfdruck möchte ich nun die Werte der Textboxen (also den Text), sowie der Buttonboxen (den Zustand) in einer XML-Datei speichern.
Das Ganze habe ich quasi schon geschafft, habe aber dennoch noch "mehrere" Fragen dazu:
1. Wie ist das Programmieren sinnvoller? Momentan habe ich in der Klasse "FORM" eine neue Klasse "SPEICHERN" erstellt, damit ich die ganzen Boxen auslesen kann. Diese Klasse (SPEICHERN) liest Text und Zustand der Boxen aus und erzeugt die XML-Datei.
Ist diese Vorgehensweise so ok, oder sollte man da besser noch über einen Zwischenschritt gehen? Ich hatte z.B. zuerst die Idee, alle Boxen in einem riesigen verschachtelten struct zu speichern. Wie macht man die Speicherung der Daten am besten ? ICh habe da keine Ahnung, bin für Tips und hinweise dankbar.
2. Ich habe bei meiner Methode das Problem, das ich den Zustand der Boxen mit "check" auslesen möchte, dieser Wert aber nicht als String (für die XML-Datei) gespeichert werden kann. Mir würde es reichen, wenn in der XML-Datei entweder "0" oder "1" bzw. "true" oder "false" stehen würde. Das ist aber wohl nicht so ohne weiteres möglich. Hat da jemand einen Tip wie man das möglichst ohne zig neue Zeilen hinkriegt ?
Anscheinend kann das Ergebnis von "check" nicht so ohne weiteres zum string umgewandelt werden.newchildnote3.SetAttribute("opt_input", testklasse.buttonbox.check);
MFG
Marco
-
zu 1.
Kommt darauf an, was Du mit den XML-Daten machen willst. Wenn Du es nur brauchst, um den aktuellen Formularzustand zu speichern, und später da weiterzumachen, könntest Du Dir mal das Application Binding (Properties.Data.ApplicationSettings) ansehen.
BTW: Wie hat die Klasse Speichern Zugriff auf die Formularobjekte? Hast Du das alles mit Zugriffsrecht internal versehen?
-
Hi
Vielen Dank für die Antwort ...
Also, soweit ich das mit ApplicationSettings verstanden habe, werden da sehr viele Werte gespeichert, mehr als ich benötige.
Der Anwender soll nur auf bestimmte Werte zugriff haben. Ich möchte somit eine Art "default-settings-Datei" erstellen, welche der Anwender verändern kann. Beim Programmstart wird die Datei dann wieder ausgelesen und die Formularobjekte werden in den Zustand gebracht, den die Datei vorgibt.
Über XML habe ich das bereits mit Nodes sehr übersichtlich lösen können, ich würde gerne bei der XML-Methode bleiben.
Wie die Klasse zugriff auf die Formularobjekte hat? Uuuppppsss, da hörts bei mir schon wieder auf, "learning by doing" ... da weis oder versteht man nicht immer was man da tut, programmieren lernt man halt nicht in 2 Wochen, ich versuchs aber mal:
ACHTUNG : NOOB-ALARM
Also die Klasse "FORM" (hier Hauptfenster):
public partial class Hauptfenster : Form { public Hauptfenster() { InitializeComponent(); } private void button_exit_Click(object sender, EventArgs e) { this.Close(); } private void button_choose_dir_Click(object sender, EventArgs e) .... .... .... private void save_Click(object sender, EventArgs e) { } public class SPEICHERN { Hauptfenster hf = new Hauptfenster(); public void write_cfg_xml(string cfg_name) { //XML-Dokument erstellen XmlDocument xmldoc = new XmlDocument(); ... ... ...
Entscheidend dürfte dabei dieser Punkt sein:
Hauptfenster hf = new Hauptfenster();
Ich weis ehrlich gesagt noch nicht einmal wie man das genau nennt, aber ohne das gehts nicht, wie gesagt, totaler Anfänger, klick and try ...
Eben aus Google zusammengesucht.Ich dachte es sei gut eine neue Klasse anzulegen, die Klasse soll nachher nicht nur das Speichern, sondern auch das Lesen der XML-Datei übernehmen. Hatte gelesen das eine solche Struktur wohl angemessen sei, obwohl ich mir nicht sicher bin ob das letztendlich so gemeint war, wie ich es gemacht habe. Immerhin habe ich ja eine art "Unterklasse" erzeugt (in der Klasse "Hauptform").
Zudem hatte ich auch schon versucht die Textfelder zu "beschreiben". Wenn sich die Funktion innerhalb der Klasse "Hauptfenster" befindet geht das, außerhalb davon geht es nicht. Dieses "Intelisense" vom Visual-Studio zeigt zwar die Textbox an und ich kann auch ohne Compilerfehler einen Wert angeben, jedoch wird in der GUI dieser Wert dann nicht angezeigt. Innerhalb der Klasse "Hauptfenster" funktioniert das wie gesagt einwandfrei.
Die Modifier (hab gelesen, das die wohl so heissen) werden vom Designer standardmässig auf "privat" gesetzt.
private System.Windows.Forms.TextBox NAME-DER-BOX;
und sollen wohl auch so gelassen werden.
Wie erwähnt, ich möchte es vernünftig machen, zumindest so gut, wie es halt am Anfang geht, ist mein allererstes Programm.
MFG
Marco
-
Nein, Du sollst doch nicht alle Properties binden:
- Solution Explorer->Properties->Settings: dort ein Eintrag erstellen mit passenden Namen und Typen, für Textbox halt ein String, für Checkbox ein boolean
- speichern. Es wird automatisch eine app.config generiert, im besten XML, wie Du es Dir wünschst.
- dann im Formeditor: Textbox wählen, Properties->Data->AppSettings->Property Bindung dort Property Text (der Textbox) wählen und ihr den app.config-Namen zueweisen,den Du dort für die Textbox angelegt hast.
-dasselbe wiederholen mit der Checkbox, nurProerty checked und deren spezifischen Eintrag.Dein Konstrukt ist mir unklar, Du hast eine klasse Hauptfenster, die eine Klasse Speichern besitzt, die wieder ein Hauptfenster generiert? Auch ist es m.E. unklug, das Hauptfenster der Speicherklasse zuzuordnen, klingt nach vielen Abhängigkeiten. Probiere erstmal, ob Punkt 1. für Dich ausreichend is, ansonsten wäre es vllt. besser, der Speicher-Klasse das Hauptformular im ctor zu übergeben (dazu stand meine Frage nach dem access level)
-
Fang erst mal damit an für jede Klasse eine eigene Datei zu erstellen.
Wie mein Vorposter bereits schrieb, so wie Dein Programm aussieht erzeugst Du die Klasse Hauptfenster 2 x. 1 x wird sie (wie üblich "automatisch" beim Programmstart) angezeigt und einmal nicht. Wahrscheinlich greifst Du auf die Form zu die Du nicht anzeigst. Das heisst Du speicherst Werte aus der Form die Du nicht anzeigst, also auch nicht ändern kannst.
Ich würde Dir raten die Methode write_cfg_xml in die Klasse Hauptfenster zu setzen und die Klasse Speichern zu löschen.
-
Mahlzeit
Erstmal recht herzlichen Dank, das ihr euch mit einem NOOB rumschlagt, ich weis, das das manchmal sehr "schwer" ist
@SeboStone:
Vielen Dank für die (zusätzlich) noch etwas ausführlichere Erklärung, so etwas hilft einem Newbie ungemein, da es dadurch noch verständlicher wird ... Danke!Mit der app.config sieht interessant aus, das Prinzip habe ich sofort verstanden. Ich habs mir auf einem Zettel notiert und werde mich da weiter einlesen, ich habs nämlich jetzt geschafft die BOOL-Werte über meine Methode in die XML zu kriegen.
Wenn ich die config über sie settings generiere, siehts leider sieht dann so aus ... da ist mir noch zuviel "Müll" drin:
http://www.pictureupload.de/pictures/200508115128_unsch_n.JPG
So sieht meine XML-Datei aus, wenn ich sie von Hand erstelle:
http://www.pictureupload.de/pictures/200508114957_sch_n.jpg
Bei app.config ist halt oben im Kopf nochsehr viel "Müll" der da nicht rein braucht ... das ist nicht sehr "benutzerfreundlich".
Könnte man das noch anpassen bzw. konfigurieren ?Zu den Hauptfenstern:
Das erklärt, warum der Wert nicht aktualisiert wird, wenn ich ihn aus der Klasse "Programm" aufrufe ..., schon verstanden ...
Ich habs jetzt mal so abgeändert:
Hauptfenster:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using System.Xml; namespace DVD_Batch_Converter { public partial class Hauptfenster : Form { public Hauptfenster() { InitializeComponent(); } private void button_exit_Click(object sender, EventArgs e) { this.Close(); } private void button_choose_dir_Click(object sender, EventArgs e) { this.folderBrowserDialog_input.ShowDialog(); //Anzeige des Verzeichnispfades in der Textbox show_path_box.Text = (folderBrowserDialog_input.SelectedPath); //Löschen der vorhandenen Einträge in der Listbox Verzeichnisliste.Items.Clear(); //Anzeigen der ermittelten Verzeichnisse in der Listbox string[] subdirs = Directory.GetDirectories(folderBrowserDialog_input.SelectedPath); { foreach(string verzeichnis in subdirs) { //lädt die anzuzeigenden Unterverzeichnisse und löscht vorstehendes Zeichen "/" string unterverzeichnisse = verzeichnis.Replace (folderBrowserDialog_input.SelectedPath, "").Remove(0,1); Verzeichnisliste.Items.Add(unterverzeichnisse); } } } private void show_path_TextChanged(object sender, EventArgs e) { } private void Verzeichnisliste_SelectedIndexChanged(object sender, EventArgs e) { } private void mark_all_dir_CheckedChanged(object sender, EventArgs e) { if (mark_all_dir.Checked==true) { for(int i = 0; i < Verzeichnisliste.Items.Count; i++) Verzeichnisliste.SetSelected(i, true); } if (mark_all_dir.Checked==false) { for(int i = 0; i < Verzeichnisliste.Items.Count; i++) Verzeichnisliste.SetSelected(i, false); } } ... ... ... //erzeugt eine XML-Datei, beim speichern sowie beim Programmstart public void write_cfg_xml(string cfg_name) { //XML-Dokument erstellen XmlDocument xmldoc = new XmlDocument(); ... ... ... //Speichern der xml-Datei xmldoc.Save(System.IO.Directory.GetCurrentDirectory() + cfg_name); } //liest eine XML-Datei, beim laden, sowie beim Programmstart public void read_cfg_xml(string cfg_name) { ... ... ... } }
Hauptprogramm:
using System; using System.IO; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace DVD_Batch_Converter { public class Program { /// <summary> /// Der Haupteinstiegspunkt für die Anwendung. /// </summary> [STAThread] public static void Main() { //startet Basiskomponenten Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); //startet Begrüssungsfester inkl. der kurzen Verzeilzeit (Anzeige über Sleep-Timer) Application.Run(new Begrüssungsfenster()); //erzeugt die "default.xml"-Konfigurationsdatei, sofern noch nicht vorhanden string cfg_name = "default.xml"; if(!File.Exists(System.IO.Directory.GetCurrentDirectory() + cfg_name)) { write_cfg_xml(cfg_name); } //startet Hauptfenter Application.Run(new Hauptfenster()); read_cfg_xml(cfg_name); } } }
Mein Problem momentan ist jetzt, das ich auf die Methode "write_cfg_xml" und "read_cfg_xml" aus der Klasse "Hauptfenster" keinen Zugriff mehr habe. Diese beiden Methoden rufe ich ja beim Programmstart jeweils einmal aus der Klasse "Programm" auf.
Objektorientierte Programmierung ist wohl nicht so einfach
... aber nun, Stück für Stück gehts ... wird zwar nicht perfekt,aber immerhin.
MFG
Marco
-
mbc schrieb:
Mein Problem momentan ist jetzt, das ich auf die Methode "write_cfg_xml" und "read_cfg_xml" aus der Klasse "Hauptfenster" keinen Zugriff mehr habe. Diese beiden Methoden rufe ich ja beim Programmstart jeweils einmal aus der Klasse "Programm" auf.
Das ist in der Tat dein Problem. Du hast kein Objekt vom Typ Hauptfenster und kannst daher nicht auf die Funktionen zugreifen.
Warum überlädst du nicht einfach die OnLoad-Methode der Hauptfesnter-Form? Dort kannst du alle Funktionen aufrufen die du in Hauptfenster definiert hast.
-
PuppetMaster2k schrieb:
Das ist in der Tat dein Problem. Du hast kein Objekt vom Typ Hauptfenster und kannst daher nicht auf die Funktionen zugreifen.
Quark! Er ist bereits im Objekt und wenn er es "anwählen" will nimmt er einfach "this".
-
SeboStone schrieb:
Quark! Er ist bereits im Objekt und wenn er es "anwählen" will nimmt er einfach "this".
Mit this kommt er aber nicht an Funktionen aus Hauptfenster, da er sich in der Klasse "Program" befindet, wo sich besagte Funktionen nämlich nicht befinden.
Wer lesen kann ist klar im Vorteil.
-
Ähhmm ... bitte nicht """"streiten"""" ... ist alles kein Problem.
Ist ja schliesslich meine Schuld das ich direkt mit so großen Aufgaben anfange. Aber der Urlaub ist knapp und ich benötige das Programm. Da es das so nicht gibt bleibt nur selber Programmieren ...
Vermutlich habe ich mich nicht richtig versträndlich ausgedrückt ...Also nochmal zur Thematik:
In der Klasse "Programm" wird das Programm ja gestartet (durch die Main-methode).
Dort möchte ich abfragen, ob die "default.xml"-Datei schon existiert, wenn nicht, soll sie erstellt werden. Die Daten die dort enthalten sind, habe ich schon fest in der Form eingegeben. Beim Erstellen dieser Datei sollen die Daten also der Form (im Hauptfenster) entnommen werden und dann in das xml eingetragen werden. Danach soll das Hauptfenster erst starten.Wenn die "default.xml" jedoch schon existiert, soll jetzt (nach dem Starten des Hauptfensters) die default.xml ausgelesen und die fest in der Form eingeschrieben Werte damit "überschrieben" werden.
Liest man die default.xml VOR dem FORM-Start, werden die eingelesenen Werte ja wieder durch die Initialisierung des Hauptfensters überschrieben, das muß also nachher gemacht werden (wie genau weis ich aber noch nicht, ich kämpfe gerade mit den "Nodes" um das XML richtig auszulesen).Die Funktion "write_cfg_xml" und "read_cfg_xml" habe ich jetzt halt direkt in der Klasse "Hauptform" hinten dran gehangen. Dadurch erhalte ich ja problemlos Zugriff auf die ganzen Formulare (Schaltflächen, Textboxen, ...).
Die Sache mit dem "on-Load überlagern" ist ziemlich heftig für einen Anfänger. Ich habe mir, seit dem Hinweis heute morgen, die Augen ""wund"" gesucht, aber ich finde nichts NOOB-taugliches was MIR das auch nur annähnerd verständlich beschreibt, das ist alles für den Anfang noch zu hoch, es war leider kein einfach verständliches Beispiel dabei.
Ich persönlich versuche die Sache so einfach und simpel wie möglich zu halten, als totaler Anfänger für das erste Mal sicherlich mehr als ratsam, auch wenn es andere "bessere" Methoden gibt. Ich muss erstmal Stück für Stück die Grundfunktionen kennenlernen. Das ist am Anfang halt sehr schwer (und viel), ich habe es halt auch nicht beigebracht bekommen.
Ich bin mehr als glücklich, das mein Programm schon sone tolle XML erstellen kann...
Um von der Klasse "Programm" aus zugriff auf die Funktionen in der Klasse "HAUPTFENSTER" zu erhalten, habe ich dort wieder das:
Hauptfenster hf = new Hauptfenster();
eingefügt.
Das habe ich auch im Internet so gefunden.
Wenn das falsch ist, bitte ich um einen etwas "präziseren" Hinweis wonach ich suchen soll um das Problem besser (oder richtig) zu lösen.Wenn ich das richtig verstanden habe, habe ich damit doch ein objekt (hf) erstellt, mit welchem ich auf die Klasse "HAUPTFENSTER" zugreifen kann.
Dieses Objekt steht jetzt in der Klasse "Programm".Funktionieren tut das jetzt alles so, was mich halt etwas irritiert ist, warum in meinem ersten Programm (vom Anfang dieses ganzen Threads) "zweimal" das Hauptfenster aufgerufen wurde, dort habe ich doch auch nur (genauso) das objekt erstellt (nur halt in der "Unter-Klasse" SPEICHERN).
Ziemlich verwirrend ...
MFG
Marco
-
Du kannst die OnLoad-Methode ziemlich einfach überschreiben, in dem du einen Doppelklick auf die Form selbst machst.
Ansonsten kannst du dir die Ereignisse im Properties-Fenster ansehen und dort einen Doppelklick machen.
-
PuppetMaster2k schrieb:
Du kannst die OnLoad-Methode ziemlich einfach überschreiben, in dem du einen Doppelklick auf die Form selbst machst.
Ansonsten kannst du dir die Ereignisse im Properties-Fenster ansehen und dort einen Doppelklick machen.
Schlag mich breit und nenn mich ... alles klar, das ist ja wirklich SUPER einfach, das kann sogar ich
Habs über das Properties-Fenter allerdings nicht sofort gefunden, mußte da erst auf dieses "Blitz-Symbol" klicken ... erst dann "erschlug" das neue Menü mit zig neuen Möglichkeiten.
Ich muß sagen ... ich bin stark begeistert ... hätte nicht gedacht, das es gerade von Microsoft so eine schöne Software gibt, das geht ja wirklich sehr komfortabel (wenn man denn mal gelernt hat damit umzugehen).
Dann kann ja jetzt die nächste Baustelle kommen ...
XML-Nodes
Das beenden der Applikation (meine "close-Lösung" ist da angeblich nicht die "feine" Art
Beim Folder-Browser-Dialog muß beim Cancel-Button noch was abgefangen werden ...Vielen Dank !!!
MFG
Marco