问题
I want to make it so the item I have selected in the list box shows its sibling elements in labels. Currently I used my XML file to get the <Name>
element and populate my list box with these <Name>
values. Now I want to make it so that whenever the <Name>
is highlighted in the list box, it will show the <Code>
related to that module in a label on the form.
i.e. If in the List Box, Algorithms and Data Structures is selected, show its Code,Capacity,Semester and Prerequisites in labels on the form. If some other module is selected, do that again for the selected module
Here is my XML:
<?xml version="1.0" encoding="utf-8" ?>
<SoftwareEngineering>
<Module>
<Name>Algorithms and Data Structures</Name>
<Code>3SFE504</Code>
<Capacity>5</Capacity>
<Semester>1</Semester>
<Prerequisite>none</Prerequisite>
</Module>
<Module>
<Name>3D Graphics I</Name>
<Code>3SFE508</Code>
<Capacity>5</Capacity>
<Semester>1</Semester>
<Prerequisite>none</Prerequisite>
</Module>
<Module>
<Name>Event-Driven Programming</Name>
<Code>3SFE513</Code>
<Capacity>10</Capacity>
<Semester>1</Semester>
<Prerequisite>none</Prerequisite>
</Module>
<Module>
<Name>Object Oriented Design</Name>
<Code>3SFE514</Code>
<Capcity>10</Capcity>
<Semester>1</Semester>
<Prerequisite>none</Prerequisite>
</Module>
<Module>
<Name>Requirements Engineering</Name>
<Code>3SFE516</Code>
<Capacity>10</Capacity>
<Semester>1</Semester>
<Prerequisite>none</Prerequisite>
</Module>
<Module>
<Name>Introduction to AI</Name>
<Code>3SFE599</Code>
<Capacity>5</Capacity>
<Semester>1</Semester>
<Prerequisite>none</Prerequisite>
</Module>
<Module>
<Name>Java Mobile Application Development</Name>
<Code>3SFE540</Code>
<Capacity>5</Capacity>
<Semester>1</Semester>
<Prerequisite>3SFE514(corequisite)</Prerequisite>
</Module>
<Module>
<Name>C# .NET Programming</Name>
<Code>3SFE541</Code>
<Capacity>5</Capacity>
<Semester>1</Semester>
<Prerequisite>3SFE514(corequisite)</Prerequisite>
</Module>
<Module>
<Name>Software Engineering Group Project</Name>
<Code>3SFE515</Code>
<Capacity>5</Capacity>
<Semester>2</Semester>
<Prerequisite>3SFE514(corequisite)</Prerequisite>
</Module>
<Module>
<Name>Software Engineering</Name>
<Code>3SFE519</Code>
<Capacity>10</Capacity>
<Semester>2</Semester>
<Prerequisite>none</Prerequisite>
</Module>
<Module>
<Name>Mobile User Interface Development</Name>
<Code>3SFE542</Code>
<Capacity>5</Capacity>
<Semester>2</Semester>
<Prerequisite>3SFE540</Prerequisite>
</Module>
<Module>
<Name>Interactive Multimedia</Name>
<Code>3MTS954</Code>
<Capacity>5</Capacity>
<Semester>2</Semester>
<Prerequisite>none</Prerequisite>
</Module>
<Module>
<Name>Concurrent Programming</Name>
<Code>3SFE555</Code>
<Capacity>5</Capacity>
<Semester>2</Semester>
<Prerequisite>none</Prerequisite>
</Module>
<Module>
<Name>Mobile Gaming</Name>
<Code>3SFE557</Code>
<Capacity>10</Capacity>
<Semester>2</Semester>
<Prerequisite>none</Prerequisite>
</Module>
<Module>
<Name>Intelligent Systems</Name>
<Code>3SFE500</Code>
<Capacity>10</Capacity>
<Semester>2</Semester>
<Prerequisite>3SFE599</Prerequisite>
</Module>
<Module>
<Name>3D Graphics II</Name>
<Code>3SFE501</Code>
<Capacity>10</Capacity>
<Semester>2</Semester>
<Prerequisite>3SFE508</Prerequisite>
</Module>
</SoftwareEngineering>
And here is how I've tried to achieve what I need:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
XDocument doc = XDocument.Load(workingDir + @"\Moduleslist.xml");
var names = doc.Root.Descendants("Module").Elements("Code").Select(b => b.Value);
var name = doc.Root.Descendants("Module").Elements("Name").Select(a => a.Value);
if (listBox1.SelectedValue == name)
{
labelCodeNumber.Text = names.ToString();
}
}
Please if someone could help me I would appreciate it
回答1:
I would go back a couple of steps and look at your design. How often will you be accessing the XML directly in your code? Reading a file each time the ListBox selected index changes seems to be a waste, not to mention if the file is not accessible, it will throw an exception.
If you are going to be accessing the XML numerous times, I would consider is creating an object to hold your XML data:
public class Module
{
public String Name { get; set; }
public String Code { get; set; }
public String Capacity { get; set; }
public String Semester { get; set; }
public String Prerequisite { get; set; }
}
Then create a collection of your Module objects when you read the XML
var modules = (from elem in doc.Root.Descendants("Module")
select new Module()
{
Name = elem.Element("Name").Value,
Code = elem.Element("Code").Value,
Capacity = elem.Element("Capacity").Value,
Semester = elem.Element("Semester").Value,
Prerequisite = elem.Element("Prerequisite").Value,
}).ToDictionary(k=>k.Name,v=>v);
(if the name elements won't be unique you can't do a dictionary and you'll have to do a list)
From that collection, you can then load the names into the listBox
listBox1.Items.AddRange(modules.Keys.ToArray());
And then in your listBox1_SelectedIndexChanged
event handler you can do sometihng like:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
labelCodeNumber.Text = modules[listBox1.SelectedValue].Code;
}
You can also consider DataBinding the Module
object to the ListBox, but I am not very savvy with it, so I can't offer much help there.
Edit: Here's how to put the collection in your code so you can access it any method.
public partial class Form1 : Form
{
private Dictionary<String, Module> modules;
public Form1()
{
this.modules = LoadXml(XDocument.Load(xmlPath);
}
private Dictionary<String, Module> LoadXml(XDocument doc)
{
return (from elem in doc.Root.Descendants("Module")
select new Module()
{
Name = elem.Element("Name").Value,
Code = elem.Element("Code").Value,
Capacity = elem.Element("Capacity").Value,
Semester = elem.Element("Semester").Value,
Prerequisite = elem.Element("Prerequisite").Value,
}).ToDictionary(k=>k.Name, v=>v);
}
}
回答2:
I think this will do what you want:
XDocument doc = XDocument.Load(Path.Combine(workingDir, @"Moduleslist.xml"));
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string name = listBox1.SelectedValue.ToString();
var propertiesFromName = (from module in doc.Root.Descendants("Module")
where module.Element("Name").Value == name
select new {Code = module.Element("Code").Value}).First();
labelCodeNumber.Text = propertiesFromName.Code;
}
This will fix your problem, but it's still bad code. You shouldn't read the whole file every time the index is changed. See below for a better solution.
Alternative (better) solution:
Create a class Module
with all properties of a module. Populate a list of Module objects from the XML file and set this as the data source for the list box. ListBox
has a DisplayMember
property that you can set to the name of the property you want to show in the ListBox
e.g. "Name". If you do it like this then the SelectedValue
property will be an instance of Module
and you can access its properties directly.
来源:https://stackoverflow.com/questions/9955609/matching-xml-elements-to-listbox-selected-item-c-sharp