Getting array of buttons to display data from a XML file? - c#

So, my XML file is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<quiz>
</answers>
</question>
<!-- More questions here -->
</quiz>
My Form1.cs looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Drawing;
namespace WindowsFormsApplication1
{
public partial class FormMain : Form
{
Basically, all four buttons had the question on them rather than the answers and underneath the bottom left button, there appeared to be a blank button. How do I get the question to display where label1 is and the answers to be on four separate buttons? Also, how will I do it when I start adding multiple questions (User obviously can't move on to the next question unless they get previous one right and difficulty can be chosen at the start to show a different set of questions).
I've been on at this for a while and I think it needs a fresh set of eyes because my relatively novice C# brain can't figure it out. Anyone help me please?

Check out the answer to this question. What is much easier to deal with is Deserialize the XML into a class you've created with a matching structure.
How to Deserialize XML document
More info here:
http://msdn.microsoft.com/en-us/library/58a18dwa.aspx

You are setting the text of every button each time around your loop:
foreach (var question in _questions)
{
button1.Text = question.QuestionText;
button2.Text = question.QuestionText;
button3.Text = question.QuestionText;
button4.Text = question.QuestionText;
}
The last time around the loop, each button will have the text set to the text of the last question.
It also looks a bit odd, as you have four buttons defined as fields of the form, yet you are creating additional buttons in your PopulateForm method but doing nothing with them.
You would be better off getting rid of the fields and working with the newly-created buttons directly:
private void PopulateForm()
{
int count = 0;
foreach (var question in _questions)
{
var button = new Button();
button.Size = new Size(60, 23);
button.Location = new Point(100, 40 + (count * 30));
button.Text = question.QuestionText;
Controls.Add(button);
count++;
}
}
You have to set the location of each button to something different, otherwise they will all show in the same place.
EDIT:
From looking at your code in your zip file, what you want is something like (assuming that your questions have four answers):
private void PopulateForm()
{
foreach (var question in _questions)
{
label1.Text = question.QuestionText;
button1.Text = question.Answers[0];
button2.Text = question.Answers[1];
button3.Text = question.Answers[2];
button4.Text = question.Answers[3];
}
}

Related

How to remove/delete Button text on when check button is clicked?

I am making this sum creator where user will have to type an answer using custom keyboard. and on check button click if answer is correct then new question is loaded.
My problem is after answering first question answer button reset to blank but when user types next answer, only one last alphabet is deleted (for example 5 from 15). and when i type 14 it shows 114 (1 from previously typed answer).
I need help to reset answer button text to blank.
I am using buttons because later i want to add more questions at the same time so user will have multiple answers to click and type.
Can anyone please help me on this? Also tell me if this is the right method to achieve what i want.
I am calling backspace function to delete previous answer and also setting text to blank.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Keyboard : MonoBehaviour
{
string word = null;
int wordIndex = -1;
string alpha = null;
string alpha2 = null;
public Text userAnswer1 = null;
public Text valueA, valueB;
public Text scoreCount;
private int a, b, answer1, score;
char[] nameChar = new char[5];
private void Start()
{
SumCreator();
}
public void nameFunc (string alphabet)
{
wordIndex++;
char[] keepchar = alphabet.ToCharArray();
nameChar[wordIndex] = keepchar[0];
alpha = nameChar[wordIndex].ToString();
word = word + alpha;
userAnswer1.text = word;
}
public void BackspaceFunction()
{
if (wordIndex >= 0)
{
wordIndex--;
alpha2 = null;
for (int i = 0; i < wordIndex + 1; i++)
{
alpha2 = alpha2 + nameChar[i].ToString();
}
word = alpha2;
userAnswer1.text = word;
}
}
public void SumCreator ()
{
a = Random.Range(0,15);
b = Random.Range(0,15);
answer1 = a + b;
valueA.text = a.ToString();
valueB.text = b.ToString();
scoreCount.text = "score " + score.ToString();
}
public void CheckAnswer()
{
Text buttonText = userAnswer1.GetComponentInChildren<Text>();
if (answer1 == int.Parse(userAnswer1.text))
{
score++;
// userAnswer1.text = string.Empty;
buttonText.text = string.Empty;
}
SumCreator();
}
}
I've edited my answer and removed the now irrelevant parts.
Once the button "Check" is clicked, first of all erase the text in the result textbox, then do the whole other logic.
To erase the text you can use next piece of code:
Text buttonText = buttonName.GetComponentInChildren<Text>();
buttonText.text = string.Empty;
You probably want to have this "buttonText" property as a global and get it once, at the start of the program instead of getting it every time the button is clicked. It won't do much difference in a small scale program, but it's a right way of thinking.
After checking your code a bit more, I can summarize your problem:
The whole logic of your program is flawed, there're many unnecessary complicated things which make it fail in several places. It is understandable, everybody goes through this stage, nothing to be ashamed or worried about. Either way it's my subjective opinion, which may be wrong.
Back to your code, all you have to do is update your result text, say "txtResult", once anything happens.
Once you click a number, do "txtResult += numberClicked".
Once you click backspace, remove last char of txtResult. Here is a question with many answers on how to do it, it's really simple.
Once you click "Check", in case it's the right number, set txtResult to empty.
Also, every time you update txtResult, you're supposed to update the UI too of course. Let's say you do it every time, it would be one line to update txtResult, and one line to update UI for each of the above 3 cases. So in total 6 lines. A check for an empty string while in "Backspace" function adds another line. My math could be wrong, but either way, it's quite short and simple approach, nothing too complicated.
You just lack relevant knowledge, otherwise you wouldn't be doing that nightmare in your Backspace function.
Regarding the "nameFunc" function, the whole 6 lines could be replaced with "txtResult += alphabet", isn't it? I'm not sure what you get in alphabet parameter, but either way, string is an array of chars, so you can also do "txtResult += alphabet[0]" instead of what you have there.
So, in total, you got it all right, the logic was right, you figured the main aspects. But you over complicated the whole thing. I believe you'll be fine after reading all this text, and wish you the best.
If you want to clear your Text object when you have succesfully entered your answer, you should not call your "BackSpace" function.
Just replace your code to this:
if (answer1 == int.Parse(userAnswer1.text))
{
score++;
userAnswer1.text = string.Empty;
This will clear the text element.
You could also look into using InputFields in Unity, which are designed for entering input and automatically support backspace and other keyboard functions.
If you do, make sure that you set the InputField's ContentType to either Integer Number or Decimal Number

C# CheckedListBox how to manipulate checked data?

Hey guys new to C# and I am trying to setup a GUI, all I want the GUI to do is have a simple file explorer with a CheckedListBox to represent selected files.
I can get the CheckedListBox to show up and click on files but I'm not sure how to continue from here, most tutorials stop here, or go too advanced with tree view and other things that seem unnecessary for what I am trying to do.
Here is my code:
Any help is appreciated and if you guys could point me in the right direction that would be awesome.
EDIT:
To rephrase my question:
I want the user to select files through the CheckedListBox (user input stops here), and for those selected files to be put in a list that my code can manipulate.
Not sure how to accomplish this after my first foreach loop (which adds all files in the selected directory to the CheckedListBox for user selection).
The second foreach loop is an attempt at this, manipulating the files so that they output their filenames after being selected. However no Messagebox shows up and I assume that their is a disconnect between the user selecting files and the codes attempt at manipulating said files.
Second Edit:
I think I figured it out I made a second button and from here it looks like I can manipulate the chosen files however I want.
Currently the code is working the way I would expect it to work.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace SelectFiles
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
checkedListBox1.CheckOnClick = true;
}
private void button1_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
MessageBox.Show(fbd.SelectedPath);
checkedListBox1.Items.Clear();
string[] files = Directory.GetFiles(fbd.SelectedPath);
foreach (string file in files)
{
checkedListBox1.Items.Add(file);
}
}
private void button2_Click_1(object sender, EventArgs e)
{
List<string> list_all_excelfiles = new List<string>();
foreach (string item in checkedListBox1.CheckedItems)
{
list_all_excelfiles.Add(item);
MessageBox.Show(Path.GetFileName(item));
}
}
}
}
First i advice you to assign Value member and Display member for each item.
Display Member will be visible to user
Value Member will we use in code
To do this first create simple custom class
public class Int_String
{
public int _int { get; set; }
public string _string { get; set; }
}
Be careful because get; set; part is important to be there since if not code will not work
Now what you need to do is create list of items with custom class like this
class YourForm : Form
{
List<Int_String> myList = new List<Int_String>(); //Create list of our custom class
public YourForm()
{
PopulateMyList();
}
private void PopulateMyList()
{
//Here read from database or get data somehow and populate our list like this
//I will populate it manually but you do it in foreach loop
myList.Add(new Int_String { _int = 0, _string = "First Item" });
myList.Add(new Int_String { _int = 1, _string = "Second Item" });
myList.Add(new Int_String { _int = 2, _string = "Third Item" });
}
}
After that you need to assign this list to your checkedListBox which you will do like this:
public YourForm()
{
PopulateMyList();
checkedListBox1.DataSource = myList;
checkedListBox1.DisplayMember = "_string";
checkedListBox1.ValueMember = "_int";
}
And now when you can manipulate with checked items like this:
for(int i = 0; i < checkedListBox1.Items.Count; i++)
{
if(checkedListBox1.Items[i].CheckedState == CheckState.Checked)
{
int itemValueMember = (checkedListBox1.Items[i] as Int_String)._int;
int itemDisplayMember = (checkedListBox1.Items[i] as Int_String)._string;
//Use these two vars for whatever you need
}
}
TWO IMPORTANT TIPS:
I am not sure for this one since i am writing all this from head but i think that visual studio will not show you that there is DisplayMember or ValueMember for checkedBox component BUT also it will not show error. Reason is that they have hidden in intentionally for idk what reason but it will work.
You are able to assign Display and Value member to a lot of components in winforms BUT for some reason checkedListBox is specific. It is specific because you MUST first assign DataSource to it and then tell it checkedListBox.DisplayMember = "_string" ...... For new guy you will ask why it is important. Simple answer is create custom list for test and add 10k items inside it and then first declare datasource and after it Display and Value member. Test how long form will need to load (get out of freeze state). After that do everything same but first declare Display and Value member and then assign datasource and test again. I am telling this from head without testing but before when i needed about 5k rows with 1st solution it took me about 30 sec and second < 1 sec. If you want to know more about it google it but for now this is pretty much info for you.

Xml node foreach loop

I'm currently trying to read a xml file and add a control for every "Mods" entry.
<Modlist>
<Mods>
<Mod>Test1</Mod>
<Version>1.0</Version>
</Mods>
<Mods>
<Mod>Test2</Mod>
<Version>2.0</Version>
</Mods>
<Mods>
<Mod>Test3</Mod>
<Version>3.0</Version>
</Mods>
</Modlist>
Basically i want to add a control to a panel for every listed mod in the xml.
XDocument Mods = XDocument.Load(#"C:\dataset.xml");
foreach (var mod in Mods.Descendants("Mods"))
{
Button modbutton = new Button();
modbutton.Text = mod.Element("Mod").Value;
panel1.Controls.Add(modbutton);
}
Its working, but its only creating one button and seems to stop.
In my example it should create 3 buttons.
What do i have to change? Whats wrong with my code?
Your code to read xml is correct but you are putting each button one over the other. Set .Location property for every Button.
ur code working perfectly, but the problem is buttons are placed in same place. u need change the position.
Try this
XDocument Mods = XDocument.Load(#"C:\dataset.xml");
int I = 10;
foreach (var mod in Mods.Descendants("Mods"))
{
Button modbutton = new Button() { Top = 10 + I, Left = 10 };
modbutton.Text = mod.Element("Mod").Value;
panel1.Controls.Add(modbutton);
I += 50;
}

Displaying a text box

I've searched the questions for an answer but couldn't quite find a clear cut example. I am trying to display a simple text box in C#. I am working with C#, ArcMap and ArcObjects. I have created a toolbar that has a button in it. Upon clicking the button, I just need a text box to appear on the page. So far, this is what I've got, but nothing is producing when I click my button. Thanks for your help in advance.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
namespace Map
{
public class ArcGISAddin4 : ESRI.ArcGIS.Desktop.AddIns.Button
{
public ArcGISAddin4()
{
}
protected override void OnClick()
{
TextBox dynamicTextBox = new TextBox();
dynamicTextBox.Text = "My First Text Box";
dynamicTextBox.Name = "First Text Box";
dynamicTextBox.Enabled = true;
}
protected override void OnUpdate()
{
}
}
}
You must add the TextBox to the surrounding container (the form for example). Otherwise the program won't know where it's supposed to be displayed.
You should add dynamicTextBox to a specific container such as form.
Such as this:
TextBox dynamicTextBox = new TextBox();
dynamicTextBox.Text = "My First Text Box";
dynamicTextBox.Name = "First Text Box";
dynamicTextBox.Enabled = true;
this.Contols.Add(dynamicTextBox);//this is a pseudo code

Make links readonly in richtextbox c#

I have a richtextbox in c# and I want to make the links that appear as readonly. Right now I can move my cursor into it and edit it. Is there any way to make it readonly?
You can set this property of a RichTextBox to make the whole text read-only
ReadOnly = true
If you would like to protect the links only but leave other text editable, please try to insert the following whether under Form1_Load or under any method you may create
You'll need to add RichTextBox.Find(string str); from the object browser
MatchCollection mc = Regex.Matches(richTextBox1.Text, #"(www[^ \s]+|http[^ \s]+)([\s]|$)", RegexOptions.IgnoreCase); // Create a new MatchCollection and match from richTextBox1.Text
for (int collection = 0; collection < mc.Count; collection++) // increase collection for every string in mc
{
if (richTextBox1.Find(mc[collection].Value, RichTextBoxFinds.None) > -1) // Find the mc value
{
richTextBox1.SelectionProtected = true; // Protect the value
}
}
So the form would look like this
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
MatchCollection mc = Regex.Matches(richTextBox1.Text, #"(www[^ \s]+|http[^ \s]+)([\s]|$)", RegexOptions.IgnoreCase);
for (int collection = 0; collection < mc.Count; collection++)
{
if (richTextBox1.Find(mc[collection].Value, RichTextBoxFinds.None) > -1)
{
richTextBox1.SelectionProtected = true;
}
}
}
}
}
Thanks,
Have a great day :)
You can change it in your code like this:
richTextBox1.ReadOnly = true;
Or you could go to your design view, check the properties for your richtextbox and set the ReadOnly attribute to true.
You should capture the change event, in such a way that you reset every change a user would like to make to the link and set it back to the original link. Save the positions of the links and update the positions if the user deletes or adds a character.
I would like to share my solution...I did try everything I found on the internet but seems I can't get exactly 100% like I want(to make a richtexbox as readonly). Then I start looking for an alternative which finally I get one to do exactly like I want.
Sometime we need to show the value with a style on it, thats why we choose richtextbox at the 1st time, then it become an issue when we unable to make it as ReadOnly. The different is I am not using the richtextbox anymore but I change it to label. Depending on how your program work, you might need to have 2 control (richtextbox & label) to hold the same value which will be switched(visible true/false) base on your requirement.
See my example here to get a ReadOnly richtextbox look alike control :
<div id="History">
<asp:Label ID="lblLACA27" runat="server" CssClass="ctlLabel"></asp:Label>
</div>
And a piece of CSS code :
#History
{
height: 100px;
float: left;
overflow: auto;
overflow-x: hidden;
}
The DIV tag which hold the LABEL will act like multiline textbox/richtextbox with scrollbar visible on it. Thats it & lets continue programming. Hope this will help someone later.

Categories

Resources