Newbie - Remember form size and location

  • Thread starter Thread starter Jonathan Ciabotti
  • Start date Start date
J

Jonathan Ciabotti

Hi all,

Just learning about C#, and am wondering if there is an easy way to allow an
app to automatically save a form's size and location. The only information
I have found on the subject requires writing to the registry, which I am
hesitant to do.

Any suggestions would be greatly appreciated.

Jonathan
 
Hi Jonathan,
The only information
I have found on the subject requires writing to the registry, which I am
hesitant to do.

Why the hesitation? Most apps that are polite enough to remember their
settings put the info in the registry. If only MS did it a bit more. We put
the code into a base form so all our forms can easily save their layout (as
well as splitter settings, tree expansion etc). Theres no easy way AFAIK.

Cheers

Doug Forster
 
Hi Jonathan,

To store information like that you can either use registry, a file in an
application folder under current user in documents and settings, or in the
startup directory or a subdirectory of that.

You can use (All in the Application class)
Registry: UserAppDataRegistry
Documents and Settings: UserAppDataPath
Program directory: StartupPath

As for the actual reading and writing of settings it gets trickier. There
is no easy way for it. Microsoft seems to encourage using xml files, in
which case you can use the ConfigurationSettings class to read the file,
but you need to write to it using one of the xml classes.


Happy coding!
Morten Wennevik [C# MVP]
 
I just put together a very comprehensive configuration system that enables
you to save parameters from Forms and even controls within the form. The
full description plus code is in the current issue of Well Formed.

http://www.bobpowell.net/currentissue.htm


--
Bob Powell [MVP]
Visual C#, System.Drawing

Image transition effects, automatic persistent configuration and
design time mouse operations all in April's issue of Well Formed
http://www.bobpowell.net/wellformed.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm

The GDI+ FAQ RSS feed: http://www.bobpowell.net/faqfeed.xml
Windows Forms Tips and Tricks RSS: http://www.bobpowell.net/tipstricks.xml
Bob's Blog: http://royo.is-a-geek.com/siteFeeder/GetFeed.aspx?FeedId=41
 
I use a xml based storage file in the application directory. here is my
class. Simply call SaveDesignToXML to save all settings and GetDesignFromXML
to load all settings. Relatively untested but feel free to use if you want.

----

using System;
using System.Windows.Forms;
using System.IO;
using System.Data;

namespace Adastra.GUI
{
/// <summary>
/// Summary description for Formscript.
/// </summary>
public class XMLFormscripting
{
private string xmlFilePath;
private string xmlBaseSchema;
private System.Windows.Forms.Form workingForm;
private DataSet ds;

/// <summary>
/// Constructor for Formscript Class
/// </summary>
/// <param name="form">The form of which we need to check for a file and
redesign the gui if one exists.</param>
public XMLFormscripting(System.Windows.Forms.Form form)
{
this.xmlFilePath = System.IO.Path.Combine(Application.StartupPath,
form.Name + ".xml");
this.xmlBaseSchema = System.IO.Path.Combine(Application.StartupPath,
"FormscriptBaseSchema.xsd");
this.workingForm = form;

if (File.Exists(xmlFilePath)) {
ds = new DataSet();
ds.ReadXml(xmlFilePath);
}
else if (File.Exists(xmlBaseSchema)) {
ds = new DataSet();
ds.ReadXmlSchema(xmlBaseSchema);
}
else {
// we need to cater for not having any appropriate files, so create one
and then reload into ds.
CreateLocalSchemaFile();
ds = new DataSet();
ds.ReadXmlSchema(xmlBaseSchema);
}
}
/// <summary>
/// CreateLocalSchemaFile - A method to protect ourselves from
programmatical error of not copying a file.
/// </summary>
private void CreateLocalSchemaFile() {
// the project did not have a local schema file to load, so create one
from raw text and it will mean
// if someone includes this in a project it will not go pop !
StreamWriter schemaFile = new StreamWriter(xmlBaseSchema,false);

schemaFile.WriteLine("<?xml version=\"1.0\" standalone=\"yes\" ?>");
schemaFile.WriteLine("<xs:schema id=\"Settings\" xmlns=\"\"
xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"
xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">");
schemaFile.WriteLine(" <xs:element name=\"Settings\"
msdata:IsDataSet=\"true\">");
schemaFile.WriteLine(" <xs:complexType>");
schemaFile.WriteLine(" <xs:choice maxOccurs=\"unbounded\">");
schemaFile.WriteLine(" <xs:element name=\"root\">");
schemaFile.WriteLine(" <xs:complexType>");
schemaFile.WriteLine(" <xs:sequence>");
schemaFile.WriteLine(" <xs:element name=\"ComponentName\"
type=\"xs:string\" minOccurs=\"0\" />");
schemaFile.WriteLine(" <xs:element name=\"Key\" type=\"xs:string\"
minOccurs=\"0\" />");
schemaFile.WriteLine(" <xs:element name=\"Value\"
type=\"xs:string\" minOccurs=\"0\" />");
schemaFile.WriteLine(" </xs:sequence>");
schemaFile.WriteLine(" </xs:complexType>");
schemaFile.WriteLine(" </xs:element>");
schemaFile.WriteLine(" </xs:choice>");
schemaFile.WriteLine(" </xs:complexType>");
schemaFile.WriteLine(" </xs:element>");
schemaFile.WriteLine("</xs:schema>");

schemaFile.Flush();
schemaFile.Close();
}

/// <summary>
/// GetDesignFromXML - method to allow the parsed form to be designed from
a saved xml file structure
/// </summary>
public void GetDesignFromXML() {
System.Windows.Forms.Control.ControlCollection ctrlCol =
workingForm.Controls;

foreach(DataTable t in ds.Tables){
foreach(DataRow r in t.Rows) {
// step through the dataset, locate the component it names.
string compName = (string)r["ComponentName"];
Control c = FindControl(null,compName);
if (c != null) {
string propName = (string)r["Key"];

switch (propName) {
case "Left":
c.Left = Convert.ToInt32(r["Value"]);
break;
case "Top":
c.Top = Convert.ToInt32(r["Value"]);
break;
case "Width":
c.Width = Convert.ToInt32(r["Value"]);
break;
case "Height":
c.Height = Convert.ToInt32(r["Value"]);
break;
case "Text":
c.Text = (string)r["Value"];
break;
} // switch
}
} // foreach(DataRow r in t.Rows)
} // foreach(DataTable t in ds.Tables
}
/// <summary>
/// SaveDesignToXML - Method allowing all current controls to be written
to an xml file for later parsing.
/// </summary>
public void SaveDesignToXML() {
System.Windows.Forms.Control.ControlCollection ctrlCol =
workingForm.Controls;
ds.Clear();
// Finally get properties for the form, and then save it all to the xml
file.
GetPropertiesForRowExport(workingForm, string.Empty);
ds.WriteXml(xmlFilePath, XmlWriteMode.WriteSchema);
}
/// <summary>
/// GetPropertiesForRowExport - Method to allow writing of a specific
controls properties to an xml file.
/// </summary>
/// <param name="c">an optional control to be parsed to output to
xml</param>
/// <param name="name">a string to pass, it is the prefix you want ie.
form1.panel.</param>
private void GetPropertiesForRowExport(Control c, string name) {
if (c != null) {
// Left Property
DataRow newRow1 = ds.Tables[0].NewRow();
newRow1["ComponentName"] = name + c.Name;
newRow1["Key"] = "Left";
newRow1["Value"] = Convert.ToString(c.Left);
ds.Tables[0].Rows.Add(newRow1);
// Top Property
DataRow newRow2 = ds.Tables[0].NewRow();
newRow2["ComponentName"] = name + c.Name;
newRow2["Key"] = "Top";
newRow2["Value"] = Convert.ToString(c.Top);
ds.Tables[0].Rows.Add(newRow2);
// Width Property
DataRow newRow3 = ds.Tables[0].NewRow();
newRow3["ComponentName"] = name + c.Name;
newRow3["Key"] = "Width";
newRow3["Value"] = Convert.ToString(c.Width);
ds.Tables[0].Rows.Add(newRow3);
// Height Property
DataRow newRow4 = ds.Tables[0].NewRow();
newRow4["ComponentName"] = name + c.Name;
newRow4["Key"] = "Height";
newRow4["Value"] = Convert.ToString(c.Height);
ds.Tables[0].Rows.Add(newRow4);
// Text Property
DataRow newRow5 = ds.Tables[0].NewRow();
newRow5["ComponentName"] = name + c.Name;
newRow5["Key"] = "Text";
newRow5["Value"] = c.Text;
ds.Tables[0].Rows.Add(newRow5);
}
if (c.Controls != null) {
foreach(Control c1 in c.Controls) {
if (c is Form) {
GetPropertiesForRowExport(c1, string.Empty);
}
else {
GetPropertiesForRowExport(c1, name + c.Name + ".");
}
}
}
}


/// <summary>
/// FindControl - function to locate a control, and any sub controls on
it.
/// </summary>
/// <param name="c">Control being parsed to check</param>
/// <param name="name">can be parsed Form1.Panel1.Panel2.TextBox1, we want
to return that exact control.</param>
/// <returns>the control that is returned.</returns>
private Control FindControl(Control c, string name) {
if (name.IndexOf(".") > 0) {
string[] splitStr = name.Split(".".ToCharArray(),2);
Control controlFound = FindControl(c,splitStr[0]);
return FindControl(controlFound, splitStr[1]);
}
else {
if (c != null) {
foreach(Control c2 in c.Controls) {
if (c2.Name == name) {
return c2;
}
}
}
else {
// the control parsed is null so we must just be dealing with the one
control on the form
foreach(Control c3 in workingForm.Controls) {
if (c3.Name == name) {
return c3;
}
}
if (workingForm.Name == name) {
// we should only get here if we have exhausted all other
possibilities.
return workingForm;

}
}
return null;
}
}
}
}
 
Thanks everyone. Gave me some interesting ideas to try out.

Have a good one,

Jon
 
Back
Top