HotDog's Blog

Hotdog (Robert Verpalen) about C# and vb.net

This blog hosted by:
http://blogs.vbcity.com      
  Home :: Syndication  :: Login

JunJuly 2008Aug
SMTWTFS
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

Articles

Archives

Topics

CONTACT

Fun but useful linkies

General

VS 2005

Wolfenstein ET

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.

Code CopyHideScrollFull


#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
edSvc;
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
;
}
}
}
}
}
. . .
posted on Friday, February 10, 2006 12:59 AM