Settings.cs
上传用户:hbhltzc
上传日期:2022-06-04
资源大小:1925k
文件大小:17k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. using System;
  2. using System.Xml;
  3. using System.Xml.Serialization;
  4. using System.Collections;
  5. using System.ComponentModel;
  6. using System.Drawing;
  7. using System.IO;
  8. using System.Reflection;
  9. using System.Threading;
  10. using System.Xml.Schema;
  11. using System.Windows.Forms;
  12. using System.Diagnostics;
  13. namespace XmlNotepad
  14. {
  15.     public delegate void SettingsEventHandler(object sender, string name);
  16. /// <summary>
  17.     /// Settings is a container for persistent settings that you want to store in a file
  18.     /// like XmlNotepad.settings.  Each setting has a name and some typed value.  The
  19.     /// deserialization process returns strings by default.  If you want a typed value
  20.     /// returned then you need to initialize the settings class with a default typed value
  21.     /// so it can figure out what type to return.  The type information is not stored
  22.     /// in the settings file.  Any type that has a corresponding TypeConverter is supported as 
  23.     /// well as Hashtable, Array and any IXmlSerializable object.
  24.     /// This class also provides some useful features that most
  25.     /// people expect to get out of their settings files, namely:
  26.     /// <list>
  27.     /// <item>
  28.     /// Watching changes on disk and automatically reloading the file, then generating
  29.     /// an event so that the hosting application can react to those changes.</item>
  30.     /// <item>
  31.     /// Transform any Uri setting to a persistent file name using the PersistentFileNames class.
  32.     /// </item>
  33.     /// </list>
  34. /// </summary>
  35. public class Settings : IDisposable
  36. {
  37.         string filename;
  38.         FileSystemWatcher watcher;
  39.         Hashtable map = new Hashtable();
  40.         System.Threading.Timer timer;
  41.         PersistentFileNames pfn = new PersistentFileNames();
  42.         /// <summary>
  43.         /// This event is raised when a particular setting has been changed.
  44.         /// A special setting named "File" is raised when the settings 
  45.         /// file has changed on disk.  You can listen to this event and call
  46.         /// Reload() if you want to automatically reload settings in this case.
  47.         /// </summary>
  48.         public event SettingsEventHandler Changed;
  49.         /// <summary>
  50.         /// Note this is an IDisposable object, so remember to call Dispose() on it during
  51.         /// application shutdown.
  52.         /// </summary>
  53.         public Settings() {
  54.         }
  55.         /// <summary>
  56.         /// This method is usually called right before you update the settings and save
  57.         /// them to disk.
  58.         /// </summary>
  59.         public void StopWatchingFileChanges(){
  60.             if (this.watcher != null){
  61.                 this.watcher.Dispose();
  62.                 this.watcher = null;
  63.             }
  64.         }
  65.         /// <summary>
  66.         /// Call this method if you know a particular setting object has changed.
  67.         /// This raises the Changed event.  This will happen automatically if you
  68.         /// change the setting object instance below.
  69.         /// </summary>
  70.         /// <param name="name"></param>
  71.         public void OnChanged(string name) {
  72.             if (Changed != null) Changed(this, name);
  73.         }
  74.         /// <summary>
  75.         /// Get or set a named setting passing the typed object to be serialized.
  76.         /// </summary>
  77.         /// <param name="name">The setting name</param>
  78.         /// <returns>The setting value or null if not found.</returns>
  79.         public object this[string name] {
  80.             get { return this.map[name]; }
  81.             set { 
  82.                 if (this.map[name] != value){
  83.                     this.map[name] = value;
  84.                     OnChanged(name); 
  85.                 }
  86.             }
  87.         }
  88.         /// <summary>
  89.         /// Reloads the settings from the current file on disk.
  90.         /// </summary>
  91.         public void Reload() {
  92.             Load(this.filename);
  93.         }
  94.         /// <summary>
  95.         /// Loads the specified settings file and deserializes values. It uses the existing 
  96.         /// settings to figure out the type to convert the strings to.  
  97.         /// </summary>
  98.         /// <param name="filename">XmlNotepad settings xml file.</param>
  99.         public void Load(string filename)
  100.         {
  101.             // we don't use the serializer because it's too slow to fire up.
  102.             XmlTextReader r = null;
  103.             try 
  104.             {
  105.                 r = new XmlTextReader(filename);                
  106.                 if (r.IsStartElement("Settings"))
  107.                 {
  108.                     while (r.Read())
  109.                     {
  110.                         if (r.NodeType == XmlNodeType.Element)
  111.                         {
  112.                             string name = r.Name;
  113.                             object o = map[name];
  114.                             if (o != null) 
  115.                             {
  116.                                 object value = null;
  117.                                 if (o is Hashtable) {
  118.                                     ReadHashTable(r, (Hashtable)o);
  119.                                 } else if (o is Array) {
  120.                                     value = ReadArray(name, (Array)o, r);
  121.                                 } else if (o is IXmlSerializable) {
  122.                                     IXmlSerializable xs = (IXmlSerializable)o;
  123.                                     xs.ReadXml(r);
  124.                                 } else {
  125.                                     string s = r.ReadString();
  126.                                     value = ConvertToType(s, o.GetType());
  127.                                 }
  128.                                 if (value != null) {                                    
  129.                                     this[name] = value;
  130.                                 }
  131.                             }
  132.                             OnChanged(name);
  133.                         }
  134.                     }
  135.                 }
  136.             }
  137.             catch(Exception)
  138.             {
  139.                 // Hey, at least we tried!
  140.             }
  141.             finally
  142.             {
  143.                 using (r) {}
  144.             }
  145.             this.FileName = filename;
  146.         }
  147.         public string FileName {
  148.             get { return this.filename; }
  149.             set {
  150.                 if (this.filename != value) {
  151.                     this.filename = value;
  152.                     StopWatchingFileChanges();
  153.                     this.watcher = new FileSystemWatcher(Path.GetDirectoryName(filename),
  154.                         Path.GetFileName(filename));
  155.                     this.watcher.Changed += new FileSystemEventHandler(watcher_Changed);
  156.                     this.watcher.EnableRaisingEvents = true;
  157.                 }
  158.             }
  159.         }
  160.         string ConvertToString(object value) {
  161.             if (value is Uri) {
  162.                 return pfn.GetPersistentFileName((Uri)value);                
  163.             } else if (value is string) {
  164.                 return (string)value;
  165.             } else {
  166.                 TypeConverter tc = TypeDescriptor.GetConverter(value.GetType());
  167.                 if (tc != null) {
  168.                     string s = tc.ConvertToString(value);
  169.                     return s;
  170.                 }
  171.                 throw new ApplicationException(string.Format(SR.TypeConvertError, value.GetType().FullName));
  172.             }
  173.         }
  174.         object ConvertToType(string value, Type type) {
  175.             if (type == typeof(Uri)) {
  176.                 return pfn.GetAbsoluteFilename(value);
  177.             } else if (type == typeof(string)) {
  178.                 return value;
  179.             } else {
  180.                 TypeConverter tc = TypeDescriptor.GetConverter(type);
  181.                 if (tc != null) {
  182.                     return tc.ConvertFromString(value);
  183.                 }
  184.                 throw new ApplicationException(string.Format(SR.TypeConvertError, type.FullName));
  185.             }
  186.         }
  187.         /// <summary>
  188.         /// Serializes property values to the settings file.
  189.         /// </summary>
  190.         /// <param name="filename">The name of the settings file to write to.</param>
  191.         public void Save(string filename) {
  192.             // make sure directory exists!
  193.             Directory.CreateDirectory(Path.GetDirectoryName(filename));
  194.             XmlTextWriter w = null;
  195.             try {
  196.                 w = new XmlTextWriter(filename, System.Text.Encoding.UTF8);
  197.                 w.Formatting = Formatting.Indented;
  198.                 w.WriteStartElement("Settings");
  199.                 foreach (string key in map.Keys) {
  200.                     object value = map[key];
  201.                     if (value != null) {
  202.                         if (value is Hashtable) {
  203.                             w.WriteStartElement(key); // container element      
  204.                             WriteHashTable(w, (Hashtable)value);
  205.                             w.WriteEndElement();
  206.                         } else if (value is Array) {
  207.                             WriteArray(w, key, (Array)value);
  208.                         } else if (value is IXmlSerializable) {
  209.                             w.WriteStartElement(key); // container element      
  210.                             IXmlSerializable xs = (IXmlSerializable)value;
  211.                             xs.WriteXml(w);
  212.                             w.WriteEndElement();
  213.                         } else {
  214.                             string s = ConvertToString(value);
  215.                             if (s != null) w.WriteElementString(key, s);
  216.                         }
  217.                     }
  218.                 }
  219.             } catch (Exception e) {
  220.                 Console.WriteLine(e.Message);
  221.             } finally {
  222.                 using (w) { 
  223.                 }
  224.             }
  225.         }
  226.         private void ReadHashTable(XmlReader r, Hashtable ht) {
  227.             Type et = typeof(string);
  228.             foreach (DictionaryEntry item in ht) {
  229.                 if (item.Value != null) {
  230.                     et = item.Value.GetType();
  231.                     break;
  232.                 }
  233.             }
  234.             if (!r.IsEmptyElement) {
  235.                 while (r.Read() && r.NodeType != XmlNodeType.EndElement) {
  236.                     if (r.NodeType == XmlNodeType.Element) {
  237.                         string key = XmlConvert.DecodeName(r.LocalName);
  238.                         string value = r.ReadString();
  239.                         ht[key] = ConvertToType(value, et);
  240.                     }
  241.                 }
  242.             }
  243.         }
  244.         
  245.         private void WriteHashTable(XmlWriter w, Hashtable value) {
  246.             try {
  247.                 foreach (DictionaryEntry item in value) {
  248.                     string key = XmlConvert.EncodeName(item.Key.ToString());
  249.                     w.WriteStartElement(key);
  250.                     object o = item.Value;
  251.                     w.WriteString(this.ConvertToString(o));
  252.                     w.WriteEndElement();
  253.                 }
  254.             } catch (Exception x) {
  255.                 Console.WriteLine(x.Message);
  256.             }
  257.         }
  258.         Array ReadArray(string name, Array a, XmlReader r) {
  259.             Type et = a.GetType().GetElementType();
  260.             ArrayList list = new ArrayList();
  261.             if (!r.IsEmptyElement) {
  262.                 while (r.Read() && r.NodeType != XmlNodeType.EndElement) {
  263.                     if (r.NodeType == XmlNodeType.Element) {
  264.                         string value = r.ReadString();
  265.                         list.Add(ConvertToType(value, et));
  266.                     }
  267.                 }
  268.             }
  269.             return (Array)list.ToArray(et);
  270.         }
  271.         void WriteArray(XmlWriter w, string key, Array array) {
  272.             w.WriteStartElement(key); // container element
  273.             try {
  274.                 string name = array.GetType().GetElementType().Name;
  275.                 foreach (object o in array) {
  276.                     string s = ConvertToString(o);
  277.                     if (s != null) w.WriteElementString(name, s);                    
  278.                 }
  279.             } catch (Exception x) {
  280.                 Console.WriteLine(x.Message);
  281.             }
  282.             w.WriteEndElement();
  283.         }
  284.         private void watcher_Changed(object sender, FileSystemEventArgs e) {
  285.             // The trick here is that the file system seems to generate lots of
  286.             // events and we don't want to have lots of dialogs popping up asking the
  287.             // user to reload settings, so we insert a delay to let the events
  288.             // settle down, then we tell the hosting app that the settings have changed.
  289.             if (e.ChangeType == WatcherChangeTypes.Changed && this.timer == null) {
  290.                 this.timer = new System.Threading.Timer(new TimerCallback(OnDelay), this, 2000, Timeout.Infinite);
  291.             }
  292.         }
  293.         void OnDelay(object state) {
  294.             OnChanged("File");
  295.             if (this.timer != null) {
  296.                 this.timer.Dispose();
  297.                 this.timer = null;
  298.             }
  299.         }
  300.         ~Settings() {
  301.             Dispose(false);
  302.         }
  303.         public void Dispose() {
  304.             Dispose(true);
  305.         }
  306.         protected virtual void Dispose(bool disposing) {
  307.             this.StopWatchingFileChanges();
  308.             if (this.timer != null) {
  309.                 this.timer.Dispose();
  310.             }
  311.             this.timer = null;
  312.             GC.SuppressFinalize(this);
  313.         }
  314.         //================================================================================
  315.         // Strong typed settings
  316.         //================================================================================
  317.         
  318.     }
  319.     /// <summary>
  320.     /// This class takes care of converting file names to a relative form that makes it easier to 
  321.     /// move the host application to different machines and still have relative file names work 
  322.     /// correctly. It also replaces well known paths with the variables %StartupPath%, %ProgramFiles, 
  323.     /// %UserProfile% and %SystemRoot%.  
  324.     /// </summary>
  325.     class PersistentFileNames {
  326.         Hashtable variables = new Hashtable();
  327.         
  328.         public PersistentFileNames() {
  329.             variables["StartupPath"] = Application.StartupPath;
  330.             variables["ProgramFiles"] = Environment.GetEnvironmentVariable("ProgramFiles");
  331.             variables["UserProfile"] = Environment.GetEnvironmentVariable("UserProfile");
  332.             variables["SystemRoot"] = Environment.GetEnvironmentVariable("SystemRoot");
  333.         }
  334.         public string GetPersistentFileName(Uri uri) {
  335.             if (!uri.IsAbsoluteUri) return uri.OriginalString;
  336.             string result = uri.OriginalString;
  337.             try {
  338.                 int len = 0;
  339.                 string path = uri.AbsolutePath;
  340.                 if (uri.IsFile && !File.Exists(uri.LocalPath)) // sanity check!
  341.                     return null;
  342.                 // replace absolute paths with variables.
  343.                 foreach (string key in variables.Keys) {
  344.                     string baseDir = (string)variables[key];
  345.                     if (!baseDir.EndsWith(Path.DirectorySeparatorChar.ToString()))
  346.                         baseDir += Path.DirectorySeparatorChar;
  347.                     Uri baseUri = new Uri(baseDir);
  348.                     Uri rel = baseUri.MakeRelativeUri(uri);
  349.                     string relPath = rel.GetComponents(UriComponents.SerializationInfoString, UriFormat.SafeUnescaped);
  350.                     Uri test = new Uri(relPath, UriKind.RelativeOrAbsolute);
  351.                     if (! test.IsAbsoluteUri) {
  352.                         // Keep track of the shortest relative path.
  353.                         if (len == 0 || relPath.Length < len) {
  354.                             result = "%" + key + "%" + relPath;
  355.                             len = relPath.Length;
  356.                         }
  357.                     }
  358.                 }
  359.             } catch (UriFormatException e) {
  360.                 // swallow any bad URI noise.
  361.                 Trace.WriteLine(e.Message);
  362.             }
  363.             return result;
  364.         }
  365.         public Uri GetAbsoluteFilename(string filename) {
  366.             try {
  367.                 // replace variables with absolute paths.
  368.                 foreach (string key in variables.Keys) {
  369.                     string var = "%" + key + "%";
  370.                     if (filename.StartsWith(var, StringComparison.CurrentCultureIgnoreCase)) {
  371.                         string baseDir = (string)variables[key];
  372.                         string relPath = filename.Substring(var.Length);
  373.                         if (!baseDir.EndsWith(Path.DirectorySeparatorChar.ToString()))
  374.                             baseDir += Path.DirectorySeparatorChar;                        
  375.                         Uri resolved = new Uri(new Uri(baseDir), relPath);
  376.                         return resolved;
  377.                     }
  378.                 }
  379.             } catch (UriFormatException e) {
  380.                 // swallow any bad URI noise.
  381.                 Trace.WriteLine(e.Message);
  382.             }
  383.             return new Uri(filename, UriKind.RelativeOrAbsolute);
  384.         }
  385.     }
  386. }