0

我正在使用 XML 元素填充 TreeView 控件。

这种方法效果很好。但我的问题是,如果 XML 文件大小达到 20MB+,我的应用程序就会冻结。有人可以帮我优化我的代码:

public void PopulateTreeView(string xmlPath)
{
    try
    {
        var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, XmlResolver = null };
        var doc = new XmlDocument();

        using (var sr = new StreamReader(xmlPath))
        {
            using (var reader = XmlReader.Create(sr, settings))
            {
                doc.Load(reader);

                //Initialize the TreeView control.
                treeView1.Nodes.Clear();
                treeView1.Invoke((MethodInvoker)(() => treeView1.Nodes.Add(new TreeNode(doc.DocumentElement.Name)))); 
                TreeNode tNode = new TreeNode();
                tNode = treeView1.Nodes[0];

                // Populate the TreeView with the DOM nodes.
                AddNode(doc.DocumentElement, tNode);
            }
        }
    }

    catch (XmlException xmlEx)
    {
        MessageBox.Show(xmlEx.Message, Path.GetFileName(xmlPath));
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

private void AddNode(XmlNode inXmlNode, TreeNode inTreeNode)
{
    XmlNode xNode;
    TreeNode tNode;
    XmlNodeList nodeList;
    int i;

    // Loop through the XML nodes until the leaf is reached.
    // Add the nodes to the TreeView during the looping process.
    if (inXmlNode.HasChildNodes)
    {
        nodeList = inXmlNode.ChildNodes;
        for (i = 0; i <= nodeList.Count - 1; i++)
        {
            xNode = inXmlNode.ChildNodes[i];
            inTreeNode.Nodes.Add(new TreeNode(xNode.Name));
            tNode = inTreeNode.Nodes[i];
            AddNode(xNode, tNode);
        }
    }
    else
    {
        inTreeNode.Text = (inXmlNode.OuterXml).Trim();
    }
}

非常感谢您的帮助!:)

- 编辑 -

我试图用 backgroundWorker 做到这一点,但我得到:

“InvalidOperationException - 正在从错误的线程调用此控件上执行的操作”

这就是我正在尝试的:

private void frmMain_Load(object sender, EventArgs e)
{
    if (!backgroundWorker.IsBusy)
        backgroundWorker.RunWorkerAsync();
}


private void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;

    if (worker.CancellationPending)
    {
        e.Cancel = true;
    }
    else
    {
        try
        {
            // SECTION 1. Create a DOM Document and load the XML data into it.
            var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, XmlResolver = null };
            var doc = new XmlDocument();

            using (var sr = new StreamReader(_xmlPath))
            {
                using (var reader = XmlReader.Create(sr, settings))
                {
                    doc.Load(reader);

                    // SECTION 2. Initialize the TreeView control.
                    treeView1.Nodes.Clear();
                    treeView1.Nodes.Add(new TreeNode(doc.DocumentElement.Name));

                    TreeNode tNode = new TreeNode();
                    tNode = treeView1.Nodes[0];

                    // SECTION 3. Populate the TreeView with the DOM nodes.
                    AddNode(doc.DocumentElement, tNode);
                    //treeView1.ExpandAll();
                }
            }
        }
        catch (XmlException xmlEx)
        {
            MessageBox.Show(xmlEx.Message, Path.GetFileName(_xmlPath));
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
}

public void AddNode(XmlNode inXmlNode, TreeNode inTreeNode)
{
    XmlNode xNode;
    TreeNode tNode;
    XmlNodeList nodeList;
    int i;

    // Loop through the XML nodes until the leaf is reached.
    // Add the nodes to the TreeView during the looping process.
    if (inXmlNode.HasChildNodes)
    {
        nodeList = inXmlNode.ChildNodes;
        for (i = 0; i <= nodeList.Count - 1; i++)
        {
            xNode = inXmlNode.ChildNodes[i];
            inTreeNode.Nodes.Add(new TreeNode(xNode.Name));
            tNode = inTreeNode.Nodes[i];
            AddNode(xNode, tNode);
        }
    }
    else
    {
        // Here you need to pull the data from the XmlNode based on the
        // type of node, whether attribute values are required, and so forth.
        inTreeNode.Text = (inXmlNode.OuterXml).Trim();
    }
}
4

1 回答 1

1

你需要做三件事。

  1. 在加载开始之前,调用SuspendLayout();
  2. 在单独的线程中加载您的 XML 以避免 GUI 锁定
  3. 使用类似下面的示例更新线程中的 gui
  4. 加载完成后调用ResumeLayout();

跨线程扩展方法示例:

using System;
using System.Windows.Forms;

public static class ControlExtensions
{
    /// <summary>
    /// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread.
    /// </summary>
    /// <param name="control"></param>
    /// <param name="code"></param>
    public static void UIThread(this Control @this, Action code)
    {
        if (@this.InvokeRequired)
        {
            @this.BeginInvoke(code);
        }
        else
        {
            code.Invoke();
        }
    }
}

扩展方法的功劳归于:如何从 C# 中的另一个线程更新 GUI?

于 2013-07-30T07:45:37.387 回答