VSTO保存配置的方法和建议

  • 发布时间:2017年4月12日 18:01
  • 作者:杨仕航
  • 分类标签: VSTO
  • 阅读(8788)
  • 评论(1)

继续挖VSTO的坑,再填上。这次挖坑是和读写配置有关。

我们写代码,经常会碰到有些数据或设置需要保存。这类东西下面都统一称为配置。

保存配置、读取配置是一件再平常不过的事情了。


保存配置一般有两种方法:写到注册表和写入到文件。

这里不讲写注册表的方法。原因如下:

1)方法简单。找个读写注册表类即可;

2)垃圾问题。如果数据保存在注册表,容易造成注册表数据过多,产生不必要的垃圾;

3)权限问题。操作一些位置的注册表,需要一定权限。麻烦。


所以,我建议大家将数据保存到文件。

保存配置文件的位置一般选择插件所在的目录。但,问题又来了。

一般我们发布插件给用户使用。用户可能会将插件安装到系统目录,例如program files文件夹。在这些系统目录中,有些电脑操作需要权限。一般程序我们可以要求需要管理员权限运行程序。但这个VSTO开发出来的是插件!插件!插件!

它是依附于Office进程运行。例如我开发一个Excel插件,不是我直接打开这个插件。而是我们打开Excel,Excel发现需要加载这个插件,才去加载插件。除非我们打开Excel时用管理员权限运行。但这种情况是少数。我们要考虑大多数情况。

那么,配置文件保存的路径只能选择其他位置。

这里,我们可以把配置文件保存到“我的文档”中。而“我的文档”的路径可以通过系统环境变量获取得到。如下代码获取:

//获取 我的文档 路径
string strPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments);

当然,你还可以在该目录下建一个目录专门保存本插件相关的数据、文件等。


路径问题解决了,剩下就是如何读写配置文件。

这个问题也不难。你可自行设计配置,如保存成xml、ini、json、txt等等。也可以是一个配置数据类,再序列化和反序列化。

这里建议保存成xml、json格式或配置数据类。因为这些操作较为方便,且结构清晰。


给大家演示xml格式的大致方法。

此处会涉及到xml文件的读写,若不懂该部分的知识,请自行了解。

考虑到一个程序可能需要保存多个配置文件。则创建一个配置操作的基类,命名为ClsBaseConfig。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

namespace Config
{
    /// <summary>
    /// 配置读写基类
    /// </summary>
    public class ClsBaseConfig
    {
        #region 属性
        protected string ConfigName { get; set; } //配置文件名(要包含后缀名)
        protected string ConfigPath { get; set; } //配置文件的路径
        protected string RootNodeName { get; set; } //配置文件根节点名
        
        //当前程序配置文件路径
        protected string ConfigFullName 
        {
            get { return Path.Combine(ConfigPath, ConfigName); }
        }
        #endregion

        #region 创建文档和节点
        /// <summary>
        /// 创建Config文件
        /// </summary>
        /// <returns>返回创建是否成功</returns>
        protected bool CreateConfig()
        {
            try
            {
                bool blnExists = File.Exists(this.ConfigFullName);
                if (blnExists) File.Delete(this.ConfigFullName);    //若文件存在,则删除

                //创建配置文件
                XmlDocument xmlDoc = new XmlDocument();
                //创建类型声明节点  
                XmlNode node = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", "");
                xmlDoc.AppendChild(node);
                //创建根节点  
                XmlNode root = xmlDoc.CreateElement(RootNodeName);
                xmlDoc.AppendChild(root);
                //保存xml文件
                xmlDoc.Save(this.ConfigFullName);

                //销毁资源
                root = null;
                node = null;
                xmlDoc = null;
                return true;
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "创建配置文件出错");
                return false;
            }
        }
        /// <summary>
        /// 创建子节点
        /// </summary>
        /// <param name="xmlDoc">xml文档</param>
        /// <param name="parentNode">父节点</param>
        /// <param name="strName">节点名</param>
        /// <param name="strValue">值</param>
        protected void CreateSubNode(XmlDocument xmlDoc, XmlNode parentNode, string strName, string strValue)
        {
            XmlNode node = xmlDoc.CreateNode(XmlNodeType.Element, strName, null);
            node.InnerText = strValue;
            parentNode.AppendChild(node);

            node = null;
        }
        #endregion

        #region 获取相关Xml对象
        /// <summary>
        /// 获取Xml配置文档
        /// </summary>
        /// <returns>返回Xml配置文档</returns>
        protected XmlDocument GetDocument()
        {
            bool blnExists = File.Exists(this.ConfigFullName);//判断文件是否存在
            //不存在则创建
            if (!blnExists)
            {
                if (!this.CreateConfig()) return null;
            }

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(this.ConfigFullName);                 //加载xml文件
            return xmlDoc;
        }
        /// <summary>
        /// 获取根节点,若没有则自动创建
        /// </summary>
        /// <param name="xmlDoc">Xml文档</param>
        /// <returns>返回根节点</returns>
        protected XmlNode GetRootNode(XmlDocument xmlDoc)
        {
            XmlNode xmlRoot = xmlDoc.SelectSingleNode(RootNodeName);//找到根节点
            //获取不到,则添加进去
            if (xmlRoot == null)
            {
                xmlRoot = xmlDoc.CreateElement(RootNodeName);
                xmlDoc.AppendChild(xmlRoot);
            }
            return xmlRoot;
        }
        /// <summary>
        /// 获取节点,若没有则自动创建
        /// </summary>
        /// <param name="xmlDoc">Xml文档</param>
        /// <param name="xmlParent">父节点</param>
        /// <param name="strName">节点名</param>
        /// <returns>返回节点</returns>
        protected XmlNode GetNode(XmlDocument xmlDoc, XmlNode xmlParent, string strName)
        {
            XmlNode xmlNode = xmlParent.SelectSingleNode(strName);
            //获取不到,则添加进去
            if (xmlNode == null)
            {
                xmlNode = xmlDoc.CreateElement(strName);
                xmlParent.AppendChild(xmlNode);
            }
            return xmlNode;
        }
        #endregion

        #region 读写方法
        /// <summary>
        /// 读取设置
        /// </summary>
        /// <typeparam name="T">值类型</typeparam>
        /// <param name="strParent">父节点</param>
        /// <param name="strName">参数名</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns>返回读取结果,没有则返回默认值</returns>
        public T ReadConfig<T>(string strParent, string strName, T defaultValue)
        {
            try
            {
                XmlDocument xmlDoc = GetDocument();                     //加载xml文件
                XmlNode xmlRoot = GetRootNode(xmlDoc);                  //获取根节点
                XmlNode xmlParent = GetNode(xmlDoc, xmlRoot, strParent);//获取父节点
                XmlNode xmlNode = GetNode(xmlDoc, xmlParent, strName);  //获取该节点

                //判断是否有内容
                if (xmlNode.InnerText == "")
                {
                    xmlNode.InnerText = defaultValue.ToString();
                    xmlDoc.Save(this.ConfigFullName);
                }
                //返回内容
                string strText = xmlNode.InnerText;
                xmlNode = null;
                xmlParent = null;
                xmlRoot = null;
                xmlDoc = null;
                return (T)Convert.ChangeType(strText, typeof(T));

            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "写入配置错误");
                return defaultValue;
            }
        }
        /// <summary>
        /// 写入设置
        /// </summary>
        /// <param name="strParent">父节点</param>
        /// <param name="strName">参数名</param>
        /// <param name="strValue">参数值</param>
        /// <returns>返回布尔值,表示是否写入成功</returns>
        public bool WriteConfig(string strParent, string strName, string strValue)
        {
            try
            {
                XmlDocument xmlDoc = GetDocument();                     //加载xml文件
                XmlNode xmlRoot = GetRootNode(xmlDoc);                  //获取根节点
                XmlNode xmlParent = GetNode(xmlDoc, xmlRoot, strParent);//获取父节点
                XmlNode xmlNode = GetNode(xmlDoc, xmlParent, strName);  //获取该节点
                xmlNode.InnerText = strValue;                           //写值
                xmlDoc.Save(this.ConfigFullName);                       //保存文件

                xmlNode = null;
                xmlParent = null;
                xmlRoot = null;
                xmlDoc = null;
                return true;
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "读取配置错误");
                return false;
            }
        }
        #endregion
    }
}

代码有点多,该类结构如下:

1)属性:保存路径,文件夹名,根节点名

2)xml操作方法

3)配置读写方法


建立基类之后,我们有需要单独保存成一个配置文件的配置,继承该类即可。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;

namespace Config
{
    /// <summary>
    /// 该插件配置文件读写类:读写配置信息
    /// </summary>
    public class ClsThisAddinConfig:ClsBaseConfig
    {
        //构造函数
        public ClsThisAddinConfig(string strPath)
        {
            ConfigPath = strPath;
            ConfigName = "Config.xml";
            RootNodeName = "Config";
        }
    }
}

写清配置文件所需的参数即可。

这里我所写的代码都没设定配置数据的名称等。可以在开发的过程中,随意添加配置。

例如,读取配置:

string strPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments);
ClsThisAddinConfig clsConfig = new ClsThisAddinConfig(strPath);

//从父节点Navgater中读取配置名show为的值,该值为布尔值。默认为true
bool oldNavSetting = clsConfig.ReadConfig<bool>("Navgater", "Show", true);

若配置文件该值不存在,则返回默认值。

再如,写入配置:

string strPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments);
ClsThisAddinConfig clsConfig = new ClsThisAddinConfig(strPath);

//写入父节点Navgater中配置名show的配置项
clsConfig.WriteConfig("Navgater", "Show", true.ToString());


读写配置,就是读写文件。

上一篇:Python操作Excel

下一篇:Excel的日期并不特殊

相关专题: VSTO的那些坑   

评论列表

lizhihua508@qq.com

lizhihua508@qq.com

杨老师写的很好,但我现在需要插件首次启动时即可读取预先写好的初始化文件,而不是启动后生成下次读取,这个该怎么操作呢?

2017-09-28 05:22 回复

新的评论

清空