Was looking for some old code in an unfinished project and stumbled upon some code that I meant to publish, but don´t believe I did :-/
It's a simple component to quickly save properties of a form and/or controls on it. A bit obsolete now because the application settings in .net 2.0 are build in and can be used as is, and with a larger scope. The truth is: I don't even use this component, but use the application settings instead :rolleyes:
Ah well, for those that are interested in such a component all the same, here it is.
#define UseDesigner
//comment this line if no designer should be used.
//the designer functionality encompasses the ability to choose from a list of
//properties when adding a control to the quicksaver.
//without the define, the property must be typed in manually.
//The only extra thing that is required when using the designer is a reference
//to System.Design.dll. If you don't want to add that reference, comment or remove
//this define
using System;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Reflection;
using System.Data;
using System.IO;
namespace Subro.Components
{
[
ProvideProperty(
"SaveProperty",
typeof(
Control))]
[
ProvideProperty(
"IncludeInSave",
typeof(
Control))]
[
ProvideProperty(
"SaveDataSource",
typeof(
ListControl))]
public class QuickSaver :
Component,
IExtenderProvider,
ISupportInitialize{
public QuickSaver()
{
}
public QuickSaver(
IContainer Container)
{
Container.Add(this);
}
#region IExtenderProvider Members
public
bool CanExtend(
object extendee)
{
return extendee is Control;
}
#endregion
const string MyCat = "Saving";
Dictionary<Control, PropertyInfo> props = new Dictionary<Control, PropertyInfo>();
[DefaultValue(null)]
[Category(MyCat)]
#if UseDesigner
[
Editor(
typeof(QuickSaver.QuickSaverEditor),
typeof(System.Drawing.Design.UITypeEditor))]
#endif
public
string GetSaveProperty(
Control c)
{
if (c ==
null)
return null;
PropertyInfo info;
if (props.TryGetValue(c,
out info))
return info.Name;
return null;
}
[
DefaultValue(
false)]
[
Category(MyCat)]
[
Description(
"Not implemented yet")]
public bool GetSaveDataSource(
ListControl c)
{
return false;
}
public void SetSaveDataSource(ListControl c,bool value)
{
}
Form form;
public void SetSaveProperty(
Control c,
string Property)
{
if (c ==
null)
return;
needcheck =
true;
if (Property ==
null)
{
props.Remove(c);
if (props.Count == 0)
form = null;
}
else{
PropertyInfo info = c.GetType().GetProperty(Property);
if (info == null) throw new Exception("Could not find property " + Property + " on " + c.GetType().Name);
props[c] = info;
}
CheckValues(); }
void setAutoLoadSave()
{
if (initializing || form ==null) return;
EventHandler ehload = new EventHandler(form_Load);
FormClosedEventHandler ehclose = new FormClosedEventHandler(form_FormClosed);
form.Load -= ehload;
form.FormClosed -= ehclose;
if (useautoloadsave)
{
form.Load += ehload;
form.FormClosed += ehclose;
}
}
void form_FormClosed(
object sender,
FormClosedEventArgs e)
{
Save();
}
void form_Load(
object sender,
EventArgs e)
{
Load();
}
private bool useautoloadsave = true;
[
DefaultValue(
true)]
[
Category(MyCat)]
[
Description(
"If this value is true, settings are automatically loaded when the form on which the controls are places is loaded and saved when that form is closed")]
public bool UseAutoLoadSave
{
get {
return useautoloadsave; }
set{
if (value == useautoloadsave) return;
useautoloadsave = value;
setAutoLoadSave();
} }
[
DefaultValue(
false)]
[
DesignerSerializationVisibility(
DesignerSerializationVisibility.Hidden)]
[
Category(MyCat)]
public bool GetIncludeInSave(
Control c)
{
return props.ContainsKey(c);
}
public
void SetIncludeInSave(
Control c,
bool value)
{
if (value == GetIncludeInSave(c)) return;
//try to get some defaults for saving (edit as you please ;-) )
string p;
if (!value)
p = null;
else
if (c
is NumericUpDown || c
is DateTimePicker)
p = "Value";
else
if (c
is CheckBox)
p = "CheckState";
else
//for the rest, use the Text property
p = "Text";
SetSaveProperty(c, p);
}
bool needcheck;
private
SavePath spath;
[
Category(MyCat)]
[
DefaultValue(
false)]
[
Description(
"Determines if the settings saved, are for the current user only, for the current computer in the application settings or in the executable folder. Only does something if FileName is empty or doesn't contain a full path. NB: User and App settings are saved using the assembly version number, so take care in use! If the version is set to upgrade itself each time with a new build (VS default setting), the file is recreated each build")]
public SavePath SaveMode
{
get { return spath; }
set{spath = value;}
}
private
string filename;
[
Category(MyCat)]
[
Description(
"The filename where the data is saved to/loaded from. If this value is empty (default), a default file will be generated depending on the setting of ForCurrentUser. If no root is given the path will also be completed in the same manner")]
[
DefaultValue(
null)]
public string FileName
{
get { return filename; }
set
{filename = value;}
}
///
<summary>
/// The complete filename to which actually will be saved to/loaded from.
/// NB, this function returns null when there are no entries
/// </summary>[
Browsable(
false)]
public string GetSaveFile(
bool LookForPrevious)
{
if (!HasEntries)
return null;
CheckValues();
string savefile = filename ==
null
? form.Name + ".dat"
: filename.Trim();
return Constants.GetSaveFile(spath, savefile, LookForPrevious);
}
///
<summary>
/// <c>true</c> is Controls are attached to this component for saving, otherwhise <c>false</c>
/// </summary>[
Browsable(
false)]
public bool HasEntries
{
get { return props.Count > 0; }
}
///
<summary>
/// uhm.. this uhm, does the loading
/// </summary>
public void Load()
{
if (!HasEntries)
return;
CheckValues();
string file = GetSaveFile(
true);
if (!
File.Exists(file))
return;
DataSet ds =
new DataSet();
ds.ReadXml(file);
DataTable dt = ds.Tables[0];
DataRow dr = dt.Rows[0];
//add check?
foreach (
KeyValuePair<
Control,
PropertyInfo> e
in props)
{
int i = dt.Columns.IndexOf(e.Key.Name);
if (i == -1) continue;
object value = Convert.ChangeType(dr[i], e.Value.PropertyType);
e.Value.SetValue(e.Key, value, null);
}
//TODO: add datasources
}
public
void Save()
{
if (!HasEntries)
return;
CheckValues();
DataSet ds =
new DataSet();
DataTable dt =
new DataTable();
//create table
object[] values =
new object[props.Count];
int i = 0;
foreach (
KeyValuePair<
Control,
PropertyInfo> e
in props)
{
dt.Columns.Add(e.Key.Name, e.Value.PropertyType);
values[i++] = e.Value.GetValue(e.Key,null);
}
dt.Rows.Add(values);
ds.Tables.Add(dt);
ds.WriteXml(GetSaveFile(
false));
//TODO: add datasources }
void CheckValues()
{
if (!needcheck || initializing)
return;
foreach (
Control c
in props.Keys)
{
Form f = c.FindForm();
if (f ==
null)
throw new Exception("Quicksaver expects controls to be added to a form to be able to load or save its values\n" + c.Name + " does not belong to a form");
if (form ==
null)
form = f;
else
if(f != form)
throw new Exception("Quicksaver expects all controls to be part of the same form. At least one control was part of another form");
}
setAutoLoadSave();
needcheck = false;
}
#region ISupportInitialize Members
bool initializing;
public void BeginInit()
{
initializing = true;
}
public
void EndInit()
{
initializing =
false;
if(!DesignMode)
CheckValues();
}
#endregion
#if UseDesigner
#region Designer
public
class QuickSaverEditor : System.Drawing.Design.
UITypeEditor{
public
override System.Drawing.Design.
UITypeEditorEditStyle GetEditStyle(
ITypeDescriptorContext context)
{
return System.Drawing.Design.UITypeEditorEditStyle.DropDown;
}
System.Windows.Forms.Design.
IWindowsFormsEditorService
public
override object EditValue(System.ComponentModel.
ITypeDescriptorContext context, System.
IServiceProvider provider,
object value)
{
Control c = context.Instance as Control;
if (c == null) return null;
// Uses the IWindowsFormsEditorService to display a
// drop-down UI in the Properties window.edSvc =
(System.Windows.Forms.Design.IWindowsFormsEditorService)provider.GetService(typeof(System.Windows.Forms.Design.IWindowsFormsEditorService));
if (edSvc !=
null)
{
ListBox lb =
new ListBox();
lb.BeginUpdate();
lb.Items.Add(
"<none>");
foreach (
PropertyInfo info
in c.GetType().GetProperties())
lb.Items.Add(info.Name);
lb.SelectedItem = value;
lb.SelectedIndexChanged += new EventHandler(lb_SelectedIndexChanged);
edSvc.DropDownControl(lb);
if (lb.SelectedIndex < 1) return null;
return lb.SelectedItem.ToString();
}
return value;
}
void lb_SelectedIndexChanged(
object sender,
EventArgs e)
{
edSvc.CloseDropDown();
}
}
#endregion
#endif
}
}
namespace Subro
{
using System.IO;
public
enum SavePath{
UserSettings, ApplicationSettings, ExecutableFolder
}
public static partial class Constants{
public
static string GetSaveFile(
SavePath spath,
string FileName)
{
return GetSaveFile(spath, FileName, false);
}
public static string GetSaveFile(SavePath spath,string FileName,bool LookForPrevious)
{
if (
System.Text.RegularExpressions.
Regex.IsMatch(
FileName, @"(?:[a-z]:\\|\\\\)[a-z]"))
{
return FileName;
}
string folder;
switch (spath)
{
case
SavePath.UserSettings:
folder = Application.UserAppDataPath;
break;
case
SavePath.ApplicationSettings:
folder = Application.CommonAppDataPath;
break;
case
SavePath.ExecutableFolder:
folder = new FileInfo(Application.ExecutablePath).DirectoryName;
LookForPrevious = false;
break;
default:
return null;
}
if (FileName[0] != '\\') FileName = "\\" + FileName;
FileName = folder + FileName;
if (LookForPrevious)
{
SearchPrevious(ref folder, ref FileName);
}
return FileName;
}
///
<summary>
/// In case of Application.UserAppDataPath and Application.CommonAppDataPath a
/// different directory is created for each assembly version (see the AssemblyInfo file
/// added to your project). This can of course be very inconvenient for loading data from
/// an older version. This method searches for previous versions.
/// </summary>
/// <param name="folder"></param>
/// <param name="FileName"></param>
static void SearchPrevious(
ref string folder,
ref string FileName)
{
FileInfo fi =
new FileInfo(FileName);
if (!fi.Exists)
{
string f =
"\\" + fi.Name;
DirectoryInfo[] dis =
new DirectoryInfo(folder).Parent.GetDirectories();
string[] files =
new string[dis.Length];
int i=0;
foreach (
DirectoryInfo di
in dis)
{
files[i++] = di.FullName + f;
}
Array.Sort<
string>(files);
for (i = files.Length - 1; i >= 0; i--)
if (
File.Exists(files[i]))
{
FileName = files[i];
break;
}
}
}
}
}
. . .