65.9K
CodeProject 正在变化。 阅读更多。
Home

设置和应用程序配置编辑器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.42/5 (8投票s)

2008 年 11 月 10 日

CPOL

2分钟阅读

viewsIcon

55433

downloadIcon

1780

在应用设置和之后编辑配置文件。描述了递归节点解析和填充树视图控件。

AppConfigEditor

引言

应用程序部署可能以多种方式发生,其中一种是安装过程。可以向安装过程中添加任何类型的脚本来修改应用程序设置。另一种方法是使用 UI 应用程序来更改配置设置。在本文中,我想展示如何操作 .config 文件或任何 XML 文档以更新其节点/属性值。

背景

此应用程序使用 TreeView、XML XPath、递归调用和控件调整大小。

使用代码

首先,让我们看看配置编辑器的 UI 是如何工作的。UI 应用程序在已安装的目录中查找扩展名为 .config 的任何文件

private void BindList() {
    try {
    string dir = string.IsNullOrEmpty(appDir) ? pplication.StartupPath : appDir;
    string[] confFiles = Directory.GetFiles(dir, "*.config");
    foreach (string fn in confFiles) {
       cbConfFiels.Items.Add(fn.Substring(fn.LastIndexOf('\\') + 1));
    }
    cbConfFiels.SelectedIndex = 0;
    } catch {
    cbConfFiels.SelectedIndex = -1;
    }
}

找到配置文件后,它将被解析并加载到树视图控件中

private void LoadConfigFileData() {
    tvNodes.Nodes.Clear();
    useXPath = false;
    cbNodes.Items.Clear();
    XPathDocument doc = null;
    try {
    appConfigFileName = localPath + "\\" + configFileName;
    XmlDocument xdoc = new XmlDocument();
    doc = new XPathDocument(appConfigFileName);
    } catch (IOException ioe) {
    string msg = configFileName + " is not found in this directory:" + 
                 localPath + "\nSelect App.config file";
    MessageBox.Show(msg);
    doc = LoadCopyFile();
    }
    LoadDocument(doc);
    ReadNodes(appConfigFileName);
}

与此同时,当前配置文件的所有可用 XPath 将被加载到 XPath 下拉列表中

/// <summary>
/// Walk through document and pick up XPath to each node
/// </summary>
/// <param name="node"></param>
void GetNode(XmlNode node) {
    int index = xPath.Length;
    xPath.Append(node.Name + "/");
    //Console.Out.WriteLine("Parent: {0}\n", xPath.ToString());

    foreach (XmlNode n in node.ChildNodes) {
    //Console.Out.WriteLine("Node name:'{0}{1}'", n.Name, 
    //    n.HasChildNodes == true ? "/" : "");
    if (n.NodeType == XmlNodeType.Element) {
        foreach (XmlAttribute at in n.Attributes) {
           //Console.Out.WriteLine("\tattribute:'{0}' 
           //   value:'{1}'", at.Name, at.Value);
        }
        if (n.HasChildNodes) {
          GetNode(n);
        }
    }
    }
    //Remove last character '/'
    xPath.Remove(index, node.Name.Length + 1);
    try{
    if(!nodeNames.Keys.Equals(xPath.ToString())){
        string xpath = xPath.ToString();//.Substring(0, xPath.Length - 1);
        if (!xPath.ToString().Equals("//")) {
        nodeNames.Add(xPath.ToString(), xpath);
        }
    }
    }catch{}
}

fig_1.JPG

通过从下拉列表中选择 XPath,它会将相应的节点加载到树视图中进行编辑。

private void cbNodes_SelectedIndexChanged(object sender, EventArgs e) {
    useXPath = true;
    string xpath = ((System.Windows.Forms.ComboBox)(sender)).Text + "*";
    XPathDocument xpDoc = new XPathDocument(appConfigFileName);
    XPathNavigator nav = xpDoc.CreateNavigator();
    XPathNodeIterator iter = nav.Select(xpath);
    iter.MoveNext();
    tvNodes.Nodes.Clear();

    string rootName = xpath.Remove(xpath.Length - 2);
    int lastIndexOf = rootName.LastIndexOf("/");
    rootName = rootName.Substring(lastIndexOf + 1, rootName.Length - lastIndexOf-1);
    XmlDocument doc = new XmlDocument();

    //Exit function no root found
    if (string.IsNullOrEmpty(rootName))
    return;

    //Add root element
    doc.LoadXml("<" + rootName + ">" + 
                iter.Current.InnerXml + "</" + 
                rootName + ">");

    XPathNavigator rootElement = doc.CreateNavigator().SelectSingleNode("/*");
    TreeNode root = new TreeNode(rootElement.LocalName);
    tvNodes.Nodes.Add(root);

    XmlNodeList addNodeList = appDoc.SelectNodes(xpath);

    //Recursive call to fill all nested nodes
    foreach (XmlNode node in addNodeList) {
    TreeNode eltNode = new TreeNode(node.Name);
    root.Nodes.Add(eltNode);
    if (node.HasChildNodes) {
        AddTreeNode(eltNode, node);
    }       
    }
    tvNodes.ExpandAll();
}

fig_2.JPG

通过单击树视图中的节点,所选节点的值将加载到值字段中,该字段可以被更新和保存。

fig_3.JPG

 /// <summary>
/// Update @key attribute value in appSettings node
/// or route to generic fuction for attributes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnUpdate_Click(object sender, EventArgs e) {
    if (!useXPath) {
    UnicodeEncoding uniEncoding = new UnicodeEncoding();
    XmlNode addNode = appDoc.SelectSingleNode("configuration/" + 
                      "appSettings/add[@key='" + nodeToEdit + "']");
    XmlNode valueNode = addNode.SelectSingleNode("@value");
    valueNode.InnerText = txtValue.Text;
    StringBuilder sb = new StringBuilder(appDoc.InnerXml.Length);
    sb.Append(appDoc.InnerXml);
    File.WriteAllLines(appConfigFileName, 
         new string[] { appDoc.InnerXml }, Encoding.UTF8);
    lblValue.Text += " - UPDATED";
    lblValue.ForeColor = Color.Blue;
    } else {
    UpdateXPath();
    }
}
/// <summary>
/// Update attribute value and save XML/Config document.
/// </summary>
private void UpdateXPath() {
    UnicodeEncoding uniEncoding = new UnicodeEncoding();
    XmlNode addNode = appDoc.SelectSingleNode(cbNodes.SelectedItem + 
                      "/@" + nodeToEdit);
    XmlNode valueNode = addNode.SelectSingleNode(".");

    valueNode.Value = txtValue.Text;
    StringBuilder sb = new StringBuilder(appDoc.InnerXml.Length);
    sb.Append(appDoc.InnerXml);
    File.WriteAllLines(appConfigFileName, 
       new string[] { appDoc.InnerXml }, Encoding.UTF8);
    lblValue.Text = nodeToEdit + " - UPDATED";
    lblValue.ForeColor = Color.Blue;
}

安装过程

创建安装项目后,将项目的主输出添加到安装过程的自定义操作中

fig_4.JPG

CustomActionData 设置为 /dir="[TARGETDIR]\" – 此值或安装目录将作为参数传递给安装程序类

fig_5.JPG

public override void Install(System.Collections.IDictionary stateSaver) {
    base.Install(stateSaver);
    Process();
}

private void Process() {
    string dir = "";
    try {
    //this is the value from setup project CustomActionData
    dir = this.Context.Parameters["dir"];
    MainForm mf = new MainForm(dir);
    mf.ShowDialog();
    mf.Close();
    } catch (Exception ex){
    StreamWriter sw = File.CreateText(dir + "SetupLog.txt");
    sw.WriteLine("Error log: " + DateTime.Now.ToLocalTime());
    if (this.Context.Parameters.Count > 0) {
        foreach (string s in this.Context.Parameters.Keys) {
        sw.WriteLine("parameter: " + s + " value: " + 
                     this.Context.Parameters[s]);
        }
    }
    sw.WriteLine(ex.Message);
    sw.Flush();
    sw.Close();
    }
}

重写 Install 方法以获取对您的应用程序的引用非常重要。如果未指定安装目录,则 Application.StartupPath 将指向您的 windows\system32 目录。如果需要一个简单的编辑器/解析器,此 UI 将适用于任何 XML 文档。附加了完整的代码。App.config 文件在构建时被转换为 ExecutbleName.exe.config 文件。

© . All rights reserved.