天涯一飘絮

导航

 

为了使我们的应用程序对用户友好,需要记住应用程序上次退出时的设置,以便再次运行这个应用程序恢复上次退出时的场景。

在上面所示的应用程序中,“每章单词数”就是需要记住的应用程序设置。

 

那么,让我们来写一个通用的抽象基类来做这件事吧。下面就是 AppConfigureBase.cs 源程序文件

01:  using System;
02:  using System.IO;
03:  using System.Xml;
04:  using System.Collections.Generic;
05:  
06:  namespace Skyiv.Common
07:  {
08:    /// <summary>
09:    /// 用于读取和保存应用程序设置的抽象基类
10:    /// </summary>
11:    public abstract class AppConfigureBase
12:    {
13:      string configureFileName;
14:      protected Dictionary<string, string> KeyValues;
15:  
16:      protected AppConfigureBase(string executeFileFullName)
17:      {
18:        configureFileName = Path.Combine(Path.GetDirectoryName(executeFileFullName),
19:          Path.GetFileNameWithoutExtension(executeFileFullName) + ".xml");
20:        KeyValues = new Dictionary<string, string>();
21:        Load();
22:      }
23:  
24:      void Load()
25:      {
26:        KeyValues.Clear();
27:        try
28:        {
29:          var doc = new XmlDocument();
30:          doc.Load(configureFileName);
31:          foreach (XmlNode node in doc.DocumentElement.ChildNodes)
32:            KeyValues.Add(node.Name, node.InnerText);
33:        }
34:        catch
35:        {
36:          // 当配置文件不存在时,不应该抛出异常。
37:          // 此时,派生类应该使用缺省值进行配置。
38:        }
39:      }
40:  
41:      public void Save()
42:      {
43:        var doc = new XmlDocument();
44:        doc.LoadXml(Api.XmlFileHeaderString + "<Settings />");
45:        foreach (var kvp in KeyValues)
46:        {
47:          var elem = doc.CreateElement(kvp.Key);
48:          elem.InnerText = kvp.Value;
49:          doc.DocumentElement.AppendChild(elem);
50:        }
51:        doc.Save(configureFileName);
52:      }
53:  
54:      protected string GetString(string key, string defaultValue)
55:      {
56:        string value;
57:        if (!KeyValues.TryGetValue(key, out value)) return defaultValue;
58:        return value;
59:      }
60:  
61:      protected void SetString(string key, string value)
62:      {
63:        KeyValues[key] = value;
64:      }
65:  
66:      protected long GetInt64(string key, long defalutValue)
67:      {
68:        return long.Parse(GetString(key, defalutValue.ToString()));
69:      }
70:  
71:      protected void SetInt64(string key, long value)
72:      {
73:        SetString(key, value.ToString());
74:      }
75:  
76:      protected DateTime GetDateTime(string key, DateTime defaultValue)
77:      {
78:        return DateTime.FromBinary(GetInt64(key, defaultValue.ToBinary()));
79:      }
80:  
81:      protected void SetDateTime(string key, DateTime value)
82:      {
83:        SetInt64(key, value.ToBinary());
84:      }
85:    }
86:  }

上述程序中第 54 行到第 84 行的 GetXXX 和 SetXXX 方法被声明为 protected,供派生类使用。如有需要,可自行增加获取和设置不同数据类型的方法。

 

哦,上述程序第 44 行中用到的 Api 类所在的 Api.cs 源程序文件如下所示:

01:  using System.Text;
02:  
03:  namespace Skyiv.Common
04:  {
05:    /// <summary>
06:    /// 一些通用的东东
07:    /// </summary>
08:    public static class Api
09:    {
10:      public static string XmlFileHeaderString = @"<?xml version=""1.0"" encoding=""UTF-8""?>";
11:      public static readonly Encoding GB18030Encoding = Encoding.GetEncoding("GB18030");
12:    }
13:  }

 

我们的应用程序应该从 AppConfigureBase 这个抽象基类派生出自己的应用程序配置类,例如下面的 AppConfigure.cs:

01:  using Skyiv.Common;
02:  
03:  namespace Skyiv.PowerWord2Snb
04:  {
05:    /// <summary>
06:    /// 应用程序设置
07:    /// </summary>
08:    sealed class AppConfigure : AppConfigureBase
09:    {
10:      static readonly string WordsPerChapterString = "WordsPerChapter";
11:  
12:      public AppConfigure(string executeFileFullName)
13:        : base(executeFileFullName)
14:      {
15:      }
16:  
17:      /// <summary>
18:      /// 每章单词数
19:      /// </summary>
20:      public long WordsPerChapter
21:      {
22:        get { return GetInt64(WordsPerChapterString, 20); }
23:        set { SetInt64(WordsPerChapterString, value); }
24:      }
25:    }
26:  }

 

下面就是用于保存应用程序设置的 PowerWord2Snb.xml 文件:

1:  <?xml version="1.0" encoding="UTF-8"?>
2:  <Settings>
3:    <WordsPerChapter>20</WordsPerChapter>
4:  </Settings>

注意,如果我们的应用程序运行时还不存在这个 XML 文件,不应该报错,而是应该使用的缺省值进行配置。然后在退出应用程序时生成一个 XML 文件来保存应用程序的设置。

 

下面就是应用程序主窗体对应的 MainForm 类所在的 MainForm.cs 源程序文件中和应用程序设置相关的内容:

01:  namespace Skyiv.PowerWord2Snb
02:  {
03:    public partial class MainForm : Form
04:    {
05:      AppConfigure appConfigure;
06:  
07:      private void MainForm_Load(object sender, EventArgs e)
08:      {
09:        appConfigure = new AppConfigure(assembly.ExecuteFileFullName);
10:        nudWordsPerChapter.Value = appConfigure.WordsPerChapter;
11:      }
12:  
13:      private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
14:      {
15:        appConfigure.WordsPerChapter = (long)nudWordsPerChapter.Value;
16:        appConfigure.Save();
17:      }
18:    }
19:  }

在上述源程序中,在应用程序主窗体装入时,初始化一个 AppConfigure 类的实例,然后再用其 WordsPerChapter 属性来设置主窗体中的 NumericUpDown 控件的值。最后,用户退出应用程序时,引发 FormClosed 事件,在这个事件处理程序中将 NumericUpDown 控件的值赋给 AppConfigure 类的 WordsPerChapter 属性,接着调用 AppConfigureBase 类的 Save 方法将应用程序的设置写入 XML 文件。

就这么简单。 微笑

 

我们已经看到了一个 GUI 界面的应用程序的例子。好吧,我们再来一个 CUI 界面的应用程序,演示稍微复杂一点的应用程序设置,这次的设置包括一个字符串、一个日期、一个整数。下面就是 AppConfigureTester.cs:

01:  using System;
02:  
03:  namespace Skyiv.Tester
04:  {
05:    class AppConfigureTester
06:    {
07:      static void Main()
08:      {
09:        try
10:        {
11:          var app = new AppConfigureTester();
12:          var cfg = new AppConfigure("AppConfigureTester.exe");
13:          app.Show(cfg);                        // 显示应用程序本次运行的设置
14:          cfg.Count += 1;                       // 每次运行增加一块金币
15:          cfg.Birth = new DateTime(1997, 7, 1); // 设置出生日期
16:          cfg.Save();                           // 退出之前保存应用程序设置
17:        }
18:        catch (Exception ex)
19:        {
20:          Console.WriteLine(ex.Message);
21:        }
22:      }
23:  
24:      void Show(AppConfigure cfg)
25:      {
26:        Console.WriteLine("姓名: " + cfg.Name);
27:        Console.WriteLine("出生: " + cfg.Birth.ToString("ddddd yyyy-MM-dd HH:mm:ss"));
28:        Console.WriteLine("金币: " + cfg.Count);
29:      }
30:    }
31:  }

 

相应的 AppConfigure.cs 如下所示:

01:  using System;
02:  using Skyiv.Common;
03:  
04:  namespace Skyiv.Tester
05:  {
06:    /// <summary>
07:    /// 应用程序设置
08:    /// </summary>
09:    sealed class AppConfigure : AppConfigureBase
10:    {
11:      static readonly string NameString = "Name";
12:      static readonly string BirthString = "Birth";
13:      static readonly string CountString = "Count";
14:  
15:      public AppConfigure(string executeFileFullName)
16:        : base(executeFileFullName)
17:      {
18:      }
19:  
20:      public string Name
21:      {
22:        get { return GetString(NameString, "无名氏"); }
23:        set { SetString(NameString, value); }
24:      }
25:  
26:      public DateTime Birth
27:      {
28:        get { return GetDateTime(BirthString, DateTime.Now); }
29:        set { SetDateTime(BirthString, value); }
30:      }
31:  
32:      public long Count
33:      {
34:        get { return GetInt64(CountString, 20); }
35:        set { SetInt64(CountString, value); }
36:      }
37:    }
38:  }

 

该 CUI 程序第一次运行的结果如下所示:

姓名: 无名氏
出生: 星期一 2010-12-27 00:03:11
金币: 20

这是因为此时还没有保存应用程序设置的 XML 文件,因此就采用了缺省值,姓名是“无名氏”,出生日期是现在的时间,金币数量为20。

 

再次运行,结果如下所示:

姓名: 无名氏
出生: 星期二 1997-07-01 00:00:00
金币: 21

可以看出,姓名不变,出生日期在 AppConfigureTester.cs 第 15 行中设置为1997年7月1日。金币数量在第 14 行中增加了一块,变为21了。

 

检查一下 AppConfigureTester.xml 文件,如下所示:

1:  <?xml version="1.0" encoding="UTF-8"?>
2:  <Settings>
3:    <Count>22</Count>
4:    <Birth>630033120000000000</Birth>
5:  </Settings>

这个文件中第 3 行的 22 说明下次运行时金币数量将增加到 22 块。第 44 行的这个很大的整数是1997年7月1日这个日期在 DateTime 结构的内部表示。而姓名一直没有修改过,所以没有保存到 XML 文件中,应用程序的每次运行都将使用缺省值“无名氏”。

posted on 2011-01-09 00:46  冰云  阅读(230)  评论(0编辑  收藏  举报