I'm trying to read an xml file and I want to do this:
A ComboBoxwhich will show all the vegetable names in the xml.
After selecting a vegetable, the second ComboBox will show the recipe names in the xml that could use the vegetable selected in the first ComboBox for cooking.
Last, with a OK button, the selected recipe will read the file path which leads to the recipe.
XML I wrote
<Vegetables>
<vegetable name="Carrot">
<recipe name="ABCrecipe">
<FilePath>C:\\</FilePath>
</recipe>
<recipe name="DEFrecipe">
<FilePath>D:\\</FilePath>
</recipe>
</vegetable>
<vegetable name="Potato">
<recipe name="CBArecipe">
<FilePath>E:\\</FilePath>
</recipe>
<recipe name"FEDrecipe">
<FilePath>F:\\</FilePath>
</recipe>
</vegetable>
</Vegetables>
C# code
public Form1()
{
InitializeComponent();
xDoc.Load("Recipe_List.xml");
}
XmlDocument xDoc = new XmlDocument();
private void Form1_Load(object sender, EventArgs e)
{
XmlNodeList vegetables = xDoc.GetElementsByTagName("Vegetable");
for (int i = 0; i < vegetables.Count; i++)
{
comboBox1.Items.Add(vegetables[i].Attributes["name"].InnerText);
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
//I'm lost at this place.
}
The first ComboBox is now able to display the vegetable names, but how do I make the 2nd ComboBox to read the recipes according to the xml file?
You can build the following Xpath and then get the recipe for the vegetable
string xpath = string.Format("//vegetable[#name='{0}']/recipe",comboboxSelectedItem);
var selectedVegetableRecipe = xdoc.SelectSingleNode(xpath);
However, as Ondrej Tucny pointed out, during the application start you can cache the xml document in a static XMLDocument and then use it the code to avoid performance overhead for each call.
First of all, you aren't storing the parsed XML anywhere. Hence in comboBox1_SelectedIndexChanged you can't work with it. You should introduce a private field (or property, whatever) in your form instead of the xDoc local variable.
If you for some odd reason wanted to keep going the way you are working with the XML file right now, you would have to lookup the selected <vegetable> element in comboBox1_SelectedIndexChanged and then process all its child <recipe> elements. However, this is unnecessarily complicated. Better way is to start with declaring the data structure and use XML serialization.
You will end up with two classes, Vegetable and Recipe, and use XmlSerializer to serialize (store into XML) and deserialize (read from XML) you data. In the form you will then work with objects and don't have to play with XML manually.
Related
To make this easier, I will show my code and then explain what im trying to do.
CODE+EXPLANATION:
First, when the user clicks on a button it goes to Other with additonal information.
private void button1_Click(object sender, EventArgs e)
=> Other("https://pastebin.com/raw/something", "Program1", "A");
private void button2_Click(object sender, EventArgs e)
=> Other("https://pastebin.com/raw/something", "Program2", "B");
Second, I download an XML document and extract neccesary information from it:
private void Other(string UniversalURL, string ProductNAME, string ProductCHANNEL)
{
//Download the Doc
XmlDocument document = new XmlDocument();
document.Load(UniversalURL);
string expandedEnvString = Environment.ExpandEnvironmentVariables("%USERPROFILE%/AppData/Local/Temp/zADU.xml");
File.WriteAllText(expandedEnvString, document.InnerXml);
XmlDocument doc = new XmlDocument();
doc.Load(expandedEnvString);
//Get the needed Nodes
XmlNode nodeXMLProgram = doc.DocumentElement.SelectSingleNode($"/{ProductNAME}");
string XMLProgram = nodeXMLProgram.InnerText;
// Creation of Button Here
}
GOAL: What I want to be able to do is use the strings, extracted from the XML and use them as variables in the creation of button, Kind of like this:
Button Program(XMLProgram) = new Button();
Program(XMLProgram).Height = 22;
Program(XMLProgram).Width = 122;
Program(XMLProgram).BackColor = Color.FromArgb(230, 230, 230);
Program(XMLProgram).ForeColor = Color.Black;
Program(XMLProgram).Name = "DynamicButton";
Program(XMLProgram).Click += new EventHandler(ProgramProgram(XMLProgram)_Click);
Program(XMLProgram).BringToFront();
Controls.Add(ProgramProgram(XMLProgram));
Would I be able to do this? Help would be appreciated! Sorry for confusing title, I don't know how to phrase it properly.
You can use Reflection to look for and set the properties of the object you are deserializing automatically, provided you have a properly formatted XML file.
Read your XML file through XDocument or XmlDocument, extract from it the type of control you need to create (button, textbox, etc), also extract the property names to set from the XML, and the values to set them to. Then create an instance of said control type, and use code like this to go through your property list from the XML and set them in your instance:
// New instance of the control (read the type from the XML and create accordingly)
var ctrlInstance = new Button();
// Get a reference to the type of the control created.
var ctrlType = ctrlInstance.GetType();
// Dictionary to contain property names and values to set (read from XML)
var properties = new Dictionary<string, object>();
foreach (var xmlProp in properties)
{
// Get a reference to the actual property in the type
var prop = ctrlType.GetProperty(xmlProp.Key);
if (prop != null && prop.CanWrite)
{
// If the property is writable set its value on the instance you created
// Note that you have to make sure the value is of the correct type
prop.SetValue(ctrlInstance, xmlProp.Value, null);
}
}
If you intend to create an entire program this way, including code, you will have to use Roslyn to compile your code at runtime, which can be somewhat complicated to put into practice. In that case, you don't need an XML file, you just need to put put all your code into a source file and compile it, then instantiate it in your own program. If you just want to create a form programmatically and handle events in its parent form, this will work fine.
I'm currently using TreeView to display a file tree for visualising diffs for a source control project. I have a "Diff" method that recursively edits an existing node in the root "Nodes" array in the TreeView, and then updates the tree afterward.
However, I've encountered an issue where the root node will duplicate for seemingly no reason, despite the debugger telling me there's a single element in the "Nodes" array at the very root of the TreeView, with no indication of an error.
I've already attempted to use "Nodes.Clear()" and then re-add the offending node, however even when clearing the array, the duplicate persists, (even when Nodes.Count is 0). I've also tried using BeginUpdate() and EndUpdate(), but to no avail.
Here's an MCVE:
public partial class BrokenControl : TreeView
{
public BrokenControl()
{
InitializeComponent();
}
public void Go(object sender, EventArgs e)
{
Nodes.Add("Root");
Nodes[0] = RecursiveEdit(Nodes[0]);
Update();
}
//This function simply recursively edits the Nodes array.
int iterations = 10;
private TreeNode RecursiveEdit(TreeNode node)
{
node.Nodes.Add(iterations.ToString());
iterations--;
if (iterations<=0)
{
return node;
}
RecursiveEdit(node.Nodes[0]);
return node;
}
}
As mentioned, I only expect there to be a single node on the TreeView when it's updated, but instead I get a duplicate node containing duplicated contents of the first.
I managed to fix the issue by using a workaround: instead of directly manipulating the Root node, saving a copy and editing, then clearing and readding, solved my issue.
Still do not know what was causing the dupe even when Nodes.Count was 0 and 1, however this seems to work.
Corrected MCVE:
public partial class BrokenControl : TreeView
{
...
public void Go(object sender, EventArgs e)
{
Nodes.Add("Root");
TreeNode savedNode = RecursiveEdit(Nodes[0]);
//This fixes it.
Nodes.Clear();
Nodes.Add(savedNode);
Update();
}
...
}
I have an app where the user logins to a list of textboxs where the users can write in them save the data then close the app and when they open it the data is still in the textboxes.
I have been researching .txt and .xml to see which is the best format to use. I have also researched XML Serialization and what code goes in the .xml file but I'm a bit lost with do I have to change the name of the textboxes so that the data loads in the right box? Theres about 15 textboxes on the page itselfs.
I have added using System.Xml.Serialization; to my form.
Also when the user logins in it open an existing form and when the user logouts it just closes the form.
I'm a bit confused on how to load the page with all the data showing, saving the data(Iv created a save button for the textbox page) and also reading the file isn't reading and loading the same?
I'm using visual studio 2012 Winforms c#
You could use the attributes for the XML and name it from the user login.
static public void CreateFile(string username)
{
XmlWriter xmlW = XmlWriter.Create(username + ".xml");
xmlW.WriteStartDocument();
xmlW.WriteStartElement("Listofboxs");
//add the box following this canvas
xmlW.WriteStartElement("box");
xmlW.WriteAttributeString("nameofbox", "exampleName");
xmlW.WriteAttributeString("valueofbox", "exampleValue");
xmlW.WriteEndElement();
//
xmlW.WriteEndElement();
xmlW.WriteEndDocument();
xmlW.Close();
}
this will allow you to create the first file with the username.
Second, to display these informations when reloading your application, here's some code:
static public Dictionary<string, string> getBoxValue(string username)
{
Dictionary<string, string> listofbox = new Dictionary<string, string>();
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(#"./" + username + ".xml");
XmlNode root = xmldoc.DocumentElement;
foreach (XmlNode box in root)
{
listofbox.Add(box.Attributes[0].Value.ToString(),box.Attributes[1].Value.ToString());
}
return listofbox;
}
For each node, the dictionnary will add a pair of string the name of the box and its value.
You can use it to fill your boxes.
I know this code may be a little unefficiency (should use "using" and such) but I hope it could help you.
I can't understanding ur problem completely. show the coding of your program what you want.
just try when your page is loading clear all textbox data.
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Text = string.Empty;
}
To read and write the xml-file you can add a dataset to your project, where you define two columns. One column for the name of the textbox and another one for the value. On the dataset you can use the Methods WriteXml and ReadXml to read and write.
To load the xml at startup you have to subscribe for the load-event of the form. And in the Formclosing-event you can write your data.
public Form1()
{
this.Load += OnLoad();
this.FormClosing += OnFormClosing();
}
private void OnLoad(object sender, EventArgs e)
{
// Read Data from Xml with the dataset (dataset.Readxml...)
}
private void OnFormClosing(object sender, FormClosingEventArgs e)
{
// Write the Data from the textboxes into the xml (dataset.writexml...)
}
To set the values of the textboxes in the load-part you can use the following code:
TextBox tb = this.Controls.Find("buttonName", true);
if(tb != null)
// set the value for the tb
I'm new to Umbraco and I like it so far, I understand how it works but I'd like to know how, and what is the best way, to create usercontrols that display some informations from umbraco's DB? When it's simple, I do it with XSL template but now I need more possibilities.
What I try to do is have a UC that connect to Umbraco's DB, fetch all documents of documentType "NewsItem" and list them in my UC.
I found this post : Umbraco: List Child Nodes in User Control but it's not quite it since I don't want to hardcode the nodeId, I want to find my news depending on DocumentType.
I now that there's an API to acces umbraco's data but did not find any exemple. I also watch lots of videos on umbraco.tv but still do not have a good idea of what's the best way to do it. There's also LINQ to Umbraco (http://our.umbraco.org/wiki/reference/api-cheatsheet/linq-to-umbraco) but not sure if it's a good way of doing this.
Also, is there a way to test the Usercontrol inside an other WebProject? What I mean is to connect to Umbraco's db in an other project, so that you don't have to go in umbraco's website to test it?
Thanks a lot!
There are several areas to your question which I'll try and address one at a time.
Using umbraco.presentation.nodefactory to get Nodes of a specific type. For this example I'm going to assume all your NewsItems are children of a specific node in this case node id 1024.
using umbraco.presentation.nodeFactory;
namespace cogworks.usercontrols
{
public partial class ExampleUserControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
var specificNode = new Node(1024);
var childNodes = specificNode.Children;
foreach(var node in childNodes)
{
if(node.NodeTypeAlias == "NewsItem")
{
//Do something with your NewsItem node!
}
}
}
}
}
This is probably not the most efficient way but is OK as an example.
An example of walking the node tree recursively and adding the found nodes to a list:
public static List<Node> SelectChildrenByNameRecursive(Node node, string docType)
{
var nodes = new List<Node>();
foreach (Node child in node.Children)
{
FindChildrenByDocType(child, docType, ref nodes);
}
return nodes;
}
private static void FindChildrenByDocType(Node node, string docType, ref List<Node> nodes)
{
if (node.NodeTypeAlias == docType)
{
nodes.Add(node);
}
foreach (Node childNode in node.Children)
{
FindChildrenByDocType(childNode, docType, ref nodes);
}
}
Again just example code...
Testing Umbraco, you'll always need to be running in a an instance of Umbraco as nodefactory is an API on top of the in memory content cache.
Further reading
http://blog.hendyracher.co.uk/umbraco-helper-class/
http://our.umbraco.org/wiki/how-tos/useful-helper-extension-methods-(linq-null-safe-access)
Little silly question, but got stuck for a long time.
I have written two classes one which is a Form (TreeDisplay class) and other which contains buiseness logic (MyTreeNode class).
TreeDisplay class contains browse button to select a file pass it to a method initiatingTree(string filename) which is in MyTreeNode class.
Now I have to pass this string parameter filename to MyTreeNode class. When I run my code the XML file which I have selected is shown in the textbox but not in treeview.
I have written the part of code but it is throwing NullReferenceException(Object reference not set to an instance of an object).
When the whole code was writeen in Form.cs the code was running successfully but on separating the business logic the exception has occured.
Can you please tell me where I am wrong?
This is the code in Browse button of TreeDisplay class (My main form):
if (open.ShowDialog(this) == DialogResult.OK)
{
txtFileName.Text = open.FileName;
MytreeNodeClass treenodeClass = new MytreeNodeClass();
treenodeClass.initiatingTree(open.FileName,treeView1);
}
Here is the code of initiatingTree() in my MyTreeNode class:
public class MytreeNodeClass
{
private readonly System.Windows.Forms.TextBox txtFileName;
private TreeView treeView1;
private readonly ToolStripStatusLabel toolStripStatusLabel1;
public string Filename
{
get { return filename; }
}
protected string filename;
public MytreeNodeClass()
{
}
public void initiatingTree(string nameofFile,TreeView treeView1)
{
try
{
//Create XML document & load the XML file.
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(nameofFile);
treeView1 = new System.Windows.Forms.TreeView();
treeView1.Nodes.Clear();
if (xmlDocument.DocumentElement != null)
{
TreeNode treeNodedoc = new TreeNode(xmlDocument.DocumentElement.Name);
treeView1.Nodes.Add(treeNodedoc);
}
On using breakpoint treeView1.Nodes.Clear(), the code comes out from this line and enters the catch block throwing NullReferenceException.
Please help to find root cause of exception. Thanks.
What is the value of treeView1 at your breakpoint?
I suggest this may be null, as the reference isn't available in your Business Logic Layer.
Updated with sample code:
public void initiatingTree(string nameofFile, TreeView treeView1)
{
try
{
//Create XML document & load the XML file.
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(nameofFile);
treeView1.Nodes.Clear();
if (xmlDocument.DocumentElement != null)
{
TreeNode treeNodedoc = new TreeNode(xmlDocument.DocumentElement.Name);
treeView1.Nodes.Add(treeNodedoc);
}
}
}
and where you call this:
if (open.ShowDialog(this) == DialogResult.OK)
{
txtFileName.Text = open.FileName;
MytreeNodeClass treenodeClass = new MytreeNodeClass();
treenodeClass.initiatingTree(open.FileName, treeView1);
}
As c.k said.
You don't have access to the usercontrols from your business layer as a standard.
May i suggest that you keep you control code in the gui code behind for simplicity.
An example how to sort your code
(Gui Layer) Codebehind for control interaction
Business Layer for data manipulation
Data Layer for database manipulations and such
Initialize the treeView1 object before accessing it.
I guess you copied and pasted, right?
Anyways here's a little note:
When you drag controls on a form in VS Designer, vs generates code for these controls "usually in InitializeComponent()". VS writes the references in your class (e.g form1.cs) like the following:
private System.Windows.Forms.TreeView treeView1;
this is just declaring a variable of type System.Windows.Forms.TreeView this variable (itself) is stored on the stack, because it's just a reference, a reference that doesn't point to any actual heap objects till now (i.e NullReference). Now this reference is useless and you can't use it unless you initialize it and tell it to point to a real object on the heap, and that's what VS does for you in the designer, it simply adds the next line to InitializComponents:
this.treeView1 = new System.Windows.Forms.TreeView();
And this is the line that you forgot to copy to the other class, which left your reference uninitialized (i.e still NullReference), hence when you tried to use it, a NullReferenceException was thrown. I guess this is your problem or at least this is how i could understand it. Forgive me if i failed to understand you!