Big Vil Big Vil - 3 months ago 30
C# Question

Xml file not available to all event methods using XDocument.Load in C#

I wanted to load an

XML
and have it available to all events.
In the application below, the
Button1
and
Button3
events use the loaded
XML
, whereas
Button2
won't and I had to load it within the event.
I am assuming that every time I load the file it is taking up more resources, which I am trying to avoid.
My questions are:
- Do I have to find a different way to populate the
Datagridview
?
- Do I need to somehow unload the
XML
file if I need to load it somewhere else to save system resources.

I am new to programming and self taught so apologize in advance if terminology is not correct.

It is an application in a Windows form with:


  • Button1 generating a listBox in ListBox1;

  • Button2 populating dataGridView1 with 2 columns;

  • Button3 populating comboBox1 list



XML is as Follows:

<?xml version="1.0" encoding="utf-8" ?>
<Config>
<Categories>
<Category Name="OneChar">
<Entry>
<Name>a</Name>
<id>1</id>
</Entry>
<Entry>
<Name>b</Name>
<id>2</id>
</Entry>
<Entry>
<Name>c</Name>
<id>3</id>
</Entry>
</Category>
<Category Name="TwoChar">
<Entry>
<Name>aa</Name>
<id>11</id>
</Entry>
<Entry>
<Name>bb</Name>
<id>22</id>
</Entry>
<Entry>
<Name>cc</Name>
<id>33</id>
</Entry>
</Category>
</Categories>
<Schemes>
</Schemes>
</Config>


Code as Follows:

using System;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Xml;
using System.Xml.XPath;

namespace List_box_multiple_query
{
public partial class Form1 : Form
{
XDocument xdoc = XDocument.Load("Config\\TestFile.xml");
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
var result = xdoc.XPathSelectElements("/Config/Categories/Category [@Name='TwoChar']/Entry/Name");
foreach (string entry in result)
{
listBox1.Items.Add(entry);
}
}

private void button2_Click(object sender, EventArgs e)
{

dataGridView1.Rows.Clear();
dataGridView1.Refresh();

XmlDocument doc = new XmlDocument();
doc.Load("Config\\testfile.xml");
XmlNodeList nodeList;
XmlNode root = doc.DocumentElement;
nodeList = root.SelectNodes("/Config/Categories/Category[@Name='OneChar']/Entry");

foreach (XmlNode entry in nodeList)
{
int n = dataGridView1.Rows.Add();
dataGridView1.Rows[n].Cells[0].Value = entry["Name"].InnerText.ToString();
dataGridView1.Rows[n].Cells[1].Value = entry["id"].InnerText.ToString();
}

}

private void button3_Click(object sender, EventArgs e)
{
var result = xdoc.XPathSelectElements("/Config/Categories/Category [@Name='TwoChar']/Entry/Name");

foreach (string entry in result)
{
comboBox1.Items.Add(entry);
}
}
}
}

Answer

First, you need to be consistently using XDocument or XmlDocument.

You can define a

 private Lazy<XmlDocument> docLazy = 
         new Lazy<XmlDocument>(() =>
             { 
                 XmlDocument doc = new XmlDocument();
                 doc.Load("Config\\TestFile.xml");
                 return doc;
             }
         );

and then use it in all the handlers

  var doc = docLazy.Value;

In this way it will be loaded from file only for the first call and then cached in memory.

My previous answer was similar but for XDocument.

reply to comments

Is there an easy way to select nodes in an XML and use their contents...?

Yes, for example

var test_nodeList  = xdoc.Descendants("Category")
    .Where(x => x.Attribute("Name").Value.Equals("OneChar"))
       .Descendants("Entry");

instead of

nodeList = root.SelectNodes("/Config/Categories/Category[@Name='OneChar']/Entry");