Conversion program storing information in array and using a combobox - c#

This is homework (I always try to point that out so it's up front). The program is a conversion program. The user picks a conversion option from a combo box and then enters a length (ie: Feet to meters) when the user hits calculate the program calculates the conversion. I have several questions because the array part is confusing me. I wanted to make sure I am going in the right direction.
I think I am using my array to populate my combo box (I used an example provided although I do not fully understand it). When the user hits the calculate button should I be storing my conversion values in the same array? something like:
string [,] conversions = { {kilometers to miles, .11111}, {miles to kilometers, .11111}}
Or am I heading in the right direction with what I have? To be clear as it is coded the array populates my combobox so if I add the extra data then it will display those numbers in the combobox, which isn't really what I am going for.
My next question, when the user hits calculate button how is it going to know what option the user has selected? I think it has something to do with index but I'm confused as far as what is actually declaring it?
*****Disregard this question. I think I found an answer*********
Answer on Updating Labels
Finally I think my last question is the page has labels next to the textboxes so if the user chooses 'Miles to kilometers" the entry textbox is going to say Miles and then the answer textbox would say Kilometers... What is that called? I need to find it in my book and cannot. I know I'm missing something but I'm trying to find either an example or where in the book it was covered and I'm simply not seeing it.
Below is my code that I currently have.
public partial class FrmConversions : Form
{
const double Miles_To_Kilometers = 1.6093;
const double Kilometers_To_Miles = 0.6214;
const double Feet_To_Meters = 0.3048;
const double Meters_To_Feet = 3.2808;
const double Inches_To_Centimeters = 2.54;
const double Centimeters_To_Inches = 0.3937;
public FrmConversions()
{
InitializeComponent();
}
private void btnExit_Click(object sender, EventArgs e)
{
this.Close();
}
private void FrmConversions_Load(object sender, EventArgs e)
{
cboConversions.Items.Clear(); //clear the combobox
string[,] conversions =
{
{"Kilometers to Miles" , "Miles to Kilometers"},
{"Feet to Meters" , "Meters to Feet"},
{"Inches to Centimeters", "Centimeters to Inches"}
};
foreach (string str in conversions)
{
cboConversions.Items.Add(str);
}
}
private void btnClear_Click(object sender, EventArgs e)
{
txtEntry.Clear();
txtAnswer.Clear();
}
public bool IsDecimal(TextBox txtEntry, string name)
{
try
{
Convert.ToDecimal(txtEntry.Text);
return true;
}
catch (FormatException)
{
MessageBox.Show(name + " must be a decimal value.", "Entry Error");
txtEntry.Focus();
return false;
}
}
private void btnCalculate_Click(object sender, EventArgs e)
{
int index = cboConversions.SelectedIndex;
if (index != -1)
{
try
{
if (IsDecimal())
{
txtAnswer.Text = ToString;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n\n" +
ex.GetType().ToString() + "\n" +
ex.StackTrace, "exception");
}
}
}
}
}
}

There are many ways to do this, a Dictionary would be neat?
In this example, the Keys of the dictionary (the strings I specified) are loaded into the combo box. Later, those strings can be used to retrieve the conversion value from the dictionary.
// Declare at the top
Dictionary<string, double> conversions = {
{ "Kilometers to Miles", Kilometers_To_Miles},
{ "Miles to Kilometers", 1 / Kilometers_To_Miles},
{ "Feet to Meters", Feet_To_Meters},
{ "Meters to Feet", 1 / Feet_To_Meters},
etc
};
// In Form Load
foreach (string str in conversions.Keys)
{
cboConversions.Items.Add(str);
}
// In btnCalculate_Click
var conversionValue = conversions[cboConversions.Text];
var convertedValue = (double)txtEntry.Text * conversionValue; // Need to validate is numeric
txtAnswer.Text = convertedValue
If you were hellbent on using arrays then this would work too, but cheats by using LINQ at the end:
// Declare at the top
object[,] conversions = {
{ "Kilometers to Miles", Kilometers_To_Miles},
{ "Miles to Kilometers", 1 / Kilometers_To_Miles},
{ "Feet to Meters", Feet_To_Meters},
{ "Meters to Feet", 1 / Feet_To_Meters},
etc
};
// In Form Load
foreach (string str in conversions)
{
cboConversions.Items.Add(str[0]);
}
// In btnCalculate_Click
var conversionValue = conversions.First(x => x[0] == cboConventions.Text)[1];
var convertedValue = (double)txtEntry.Text * conversionValue; // Need to validate is numeric
txtAnswer.Text = convertedValue

Related

how to stop text changed texbox from runing contains text code?

How would I stop text changed from running if statement? because after I type {} the code runs, but if I type any letter or press enter after I type {} the code keeps on making new labels in every letter typed or entered.
This is for WPF c#
private void TextBox_TextChanged(object sender, EventArgs e)
{
if (textBox.Text.Contains("{") && textBox.Text.Contains("}"))
{
DraggableLabel ag = new DraggableLabel();
ag.Name = "A";
ag.Content = "you have bracket"; //(i + 1).ToString();
ag.BorderBrush = Brushes.Black;
ag.BorderThickness = new Thickness(2, 2, 2, 2);
DesigningCanvas.Children.Add(ag);
ab = ag;
}
}
Notwithstanding the comments about avoiding creating UI elements in event handlers, what you need is a system that only activates if there are new { } pairs in the textbox. Perhaps something like:
private int brasProcessed = 0;
private void TextBox_TextChanged(object sender, EventArgs e)
{
int countOpenBra = textBox.Text.Count(c => c == '{');
int countCloseBra = textBox.Text.Count(c => c == '}');
//if there is a matched pair of {} (equal counts) and more { have appeared than we know we've processed before...
if (countOpenBra == countCloseBra && countOpenBra > brasProcessed)
{
DraggableLabel ag = new DraggableLabel();
ag.Name = "A";
ag.Content = "you have bracket"; //(i + 1).ToString();
ag.BorderBrush = Brushes.Black;
ag.BorderThickness = new Thickness(2, 2, 2, 2);
DesigningCanvas.Children.Add(ag);
ab = ag;
//mark the current count of {} as processed so the code will not fire again until someone adds a new { } pair
brasProcessed = countOpenBra;
}
}
Now this code will only fire when new pairs of { } are added. Every time you add a { } pair the code will run. It does not cater for deleted. It does not cater for multiples if a large amount of text containing multiple { } is pasted in. It hence likely needs some improvement but as others have noted you didn't tell us what you were trying to do, only that your solution for it was broken, and alas the solution didn't really allow us to infer what you're trying to do

Displaying Multiple Arrays

I have a project where I have to take in input of names, weights, and heights and put them into arrays and display them into a TextBox like this
name = "..."
weight = "..."
height= "..."
I have been able to populate my arrays but I do not understand how to it output it like the example above. Currently my output is all names, THEN all weights then all heights. Could someone explain how I would be able to make it display like the example? The code I have so far is
private void ShowButton_Click(object sender, EventArgs e)
{
txtShow.Text += string.Join(System.Environment.NewLine, nameArray);
txtShow.Text += string.Join(System.Environment.NewLine, weightArray);
txtShow.Text += string.Join(System.Environment.NewLine, heightArray);
}
private void AddButton_Click(object sender, EventArgs e)
{
if (this.index < 10)
{
nameArray[this.index] = nameBox.Text;
weightArray[this.index] = double.Parse(weightBox.Text);
heightArray[this.index] = double.Parse(heightBox.Text);
this.index++;
}
}
The array can store up to 10 values and I am required to use arrays and not lists.
You Should::::: Lots of ways to optimize what you're trying to do, but this is homework and you don't want to look like you're the world's greatest programmer -- you want to do the project like the prof is expecting you to. So creating classes and joining lists is not part of your particular solution set. Try:
PS - on first answer, I tried to keep my suggestion code as close to yours as possible - to answer your question without changing your code. Another commenter suggested that contantly updating a textbox.Text will lead to blinking issues. If that happens to you, I'd suggest using a temporary string as I've edited my text to do.
I know this is homework - so I'm not suggesting any grand optimizations that will make you look like you've been getting your homework done at SO.
EDIT You've asked for a way to detect empty. Based on my understanding of your code and keeping it simple, try:
private void AddButton_Click(object sender, EventArgs e)
{
if (this.index < 10)
{
if(nameBox.Text.Length==0||weightBox.Text.Length==0||heightBox.Text.Length==0){
MessageBox.Show("You must enter a name, weight, and height!");
}else{
nameArray[this.index] = nameBox.Text;
weightArray[this.index] = double.Parse(weightBox.Text);
heightArray[this.index] = double.Parse(heightBox.Text);
this.index++;
nameBox.Text = "";
weightBox.Text = "";
heightBox.Text = "";
}
}
}
private void ShowButton_Click(object sender, EventArgs e)
{ string myString = "";
for(int i=0;i<nameArray.Length;i++)
{
myString+= "Name: "+nameArray[i]+", ";
myString += "Weight: "+weightArray[i]+", ";
myString += "Height: "+heightArray[i]+"\n");
}
txtShow.Text = myString;
}
NOTE Textboxes have validation methods which will do the work of my IF/THEN statement in my revised edit to find empties. If you think the prof is looking for form (control) validation instead of codebehind IF/THEN, let me know and I'll help with that.
Okay - you mentioned the need to sort. To do that, we need to use some way of grouping the input data. We could use Dictionary or class. Let's go with class:
Putting it all together: Have a look at this potential solution - if you think it's too complicated for what your homework should look like, we can try to simplify. Let me know:
public class Person{
public string Name {get;set;}
public double Height {get;set;}
public double Weight {get; set;}
public string Print(){
return "Name: "+Name+", Height: "+Height.ToString()+", Weight: "+Weight.ToString()+"\r\n";
}
}
Person[] People = new Person[10];
int thisIndex = 0;
private void AddButton_Click(object sender, EventArgs e)
{
if (this.index < 10)
{
if(nameBox.Text.Length==0||weightBox.Text.Length==0||heightBox.Text.Length==0)
{
MessageBox.Show("You must enter a name, weight, and height!");
}else{
Person p = new Person();
p.Name = nameBox.Text;
p.Weight = double.Parse(weightBox.Text);
p.Height = double.Parse(heightBox.Text);
People[thisIndex] = p;
thisIndex++;
nameBox.Text = "";
weightBox.Text = "";
heightBox.Text = "";
}
}
}
private void ShowButton_Click(object sender, EventArgs e)
{
People = People.OrderBy(p=>p.Name).ToArray();
string myString = "";
for(int i=0;i<10;i++)
{
if(People[I]!=null){
myString+= People[I].Print();
}
}
txtShow.Text = myString;
}
You should create a class for this purpose. A class enables you to create your own custom types by grouping together variables of three types (string,double and double):
public class Person
{
public string Name { get; set; }
public double Weight { get; set; }
public double Height { get; set; }
public override string ToString()
{
return Name + " " + Weight + " " + Height;
}
}
Then:
Person[] persons = new Person[10];
private void AddButton_Click(object sender, EventArgs e)
{
persons[index] = new Person
{
Name = nameBox.Text,
Weight = double.Parse(weightBox.Text),
Height = double.Parse(heightBox.Text)
};
index++;
}
And finally (look at the ShowButton's code that now is one line):
txtShow.Text += string.Join(System.Environment.NewLine, persons.AsEnumerable());
Linq solution:
private void ShowButton_Click(object sender, EventArgs e) {
int n = Math.Min(Math.Min(nameArray.Length, weightArray.Length), heightArray.Length));
txtShow.Text = String.Join(Environment.NewLine, Enumerable
.Range(0, n)
.Select(i => string.Format("Name: {0}, Weight: {1}, Height: {2}",
nameArray[i], weightArray[i], heightArray[i])));
}
Try avoiding txtShow.Text += fragments, especially in loops (each Textchanging means redrawing and thus blinking)

Return value from method

I am creating calculator with 20 textboxes - 10 for input, 10 for output. After creating a method into which I put parameter(defined in the first 10 textboxes) I return value to main method.
To get all 10 values is it really necessary to write code for all 10 or more text boxes as I have already started or there is smarter way how to pass into the method textbox parameters and return multiple values at once?
UPDATE:
As you recomended I created List of Tuples and used foreach loop to loop through them, but now i get error:
Error 1 Cannot implicitly convert type 'int' to 'string'. Could you help me to point out where the problem is?
private void button1_Click(object sender, EventArgs e)
{
List<Tuple<TextBox,TextBox>> tuple1 = new List<Tuple<TextBox,TextBox>>();
tuple1.Add(Tuple.Create(textBox1, textBox2));
tuple1.Add(Tuple.Create(textBox3, textBox4));
tuple1.Add(Tuple.Create(textBox5, textBox6));
tuple1.Add(Tuple.Create(textBox7, textBox8));
foreach (Tuple<TextBox,TextBox> box in tuple1)
{
var inputBox = box.Item1;
var outputBox = box.Item2;
outputBox.Text = MethodA(Convert.ToInt32(inputBox.Text));
}
}
private int MethodA(int Parameter1)
{
int A = Parameter1;
int B = 20;
int C;
if (A == 16 && B == 20) { C = 15; } else if (A == 20 && B == 20) { C = 25; } else { C = 0; };
return C;
}
You could store all the input-output textbox combination in the constructor:
private List<Tuple<TextBox, TextBox>> textBoxes = new List<Tuple<TextBox, TextBox>>();
public Form1() {
InitializeComponents();
textBoxes.add(Tuple.Create(textBox1, textBox4);
// ...
}
And then, in button1_Click, just iterate over all the textboxes:
foreach (Tuple<TextBox, TextBox> boxes in textBoxes) {
var inputBox = boxes.Item1;
var outputBox = boxes.Item2;
outputBox.Text = MethodA(Convert.ToInt32(inputBox.Text));
}
This might not be the best answer, but it would work:
public class Extensions
{
public MethodA(this TextBox tb)
{
tb.Text = (Convert.ToInt32(tb.Text) + 5).ToString();
}
}
now you can just call:
textBox1.MethodA();
textBox2.MethodA();
...etc.
This isn't necessarily recommended, but it's one way you could simply doing this multiple times.
If you won't be repeating this, it'd probably be better to just inline the logic the same way:
textBox1.Text = (Convert.ToInt32(textBox1.Text) + 5).ToString();
textBox2.Text = (Convert.ToInt32(textBox2.Text) + 5).ToString();
textBox3.Text = (Convert.ToInt32(textBox3.Text) + 5).ToString();

Check each string value in dictionary for specific characters c#

I am trying to read through a dictionary and get all the values in it then check if the value in the dictionary location is equal to (A) when a button is clicked
if the value in the dictionary ends with (A) then the word "correct" is printed , else "incorrect is printed"
but that happens when i click the button is that the correctness and in-correctness of each value is printed. so it does identify the correct answer and the incorrect answer but i only need it to print out either correct of incorrect
the issue occurs in the OnGUI function.
the code allows for a random key which are questions to be selected on button click and its values which are answers displayed as buttons , you then click a button . correct answers are the values that end with (A) . bu clicking the buttons which are displayed with the value name you will check if you have selected the correct answer but there is a slight problem with it . it prints out the correctness and in-correctness of each value in the selected key
here is the entire code
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class testQuestions : MonoBehaviour {
Dictionary<string, string[]> dictionary = new Dictionary<string, string[]>();
string []vl ;
string ky;
int Qnum;
string A;
int indx;
// Use this for initialization
void Start () {
dictionary.Add("ups", new string[] {"updegree", "popup (A)"});
dictionary.Add("down aroud the place like this ", new string[] {"sun", "bun(A)","art"});
dictionary.Add("left", new string[] {"higi (A)", "migi"});
dictionary.Add("right", new string[] {"een", "yyo(A)"});
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown("q"))
{
GenerateRandoms();
}
}
void GenerateRandoms()
{
string[] keys = new string[dictionary.Count];//get the dictionary count and store in array
dictionary.Keys.CopyTo(keys, 0);
var index = Random.Range(0, keys.Length);
var key = keys[index];
var value = dictionary[key];
ky= key;
vl = value;
foreach (string ku in value)
{
// create buttons with the ku text as the button text
indx = index;
Qnum +=1;
A = ku;
}
//---------- remove each after answer button click
//dictionary.Remove(key); // remove key after it is already displayed. this must only be exicuted at the end of the function
}
void OnGUI ()
{
int charlength = 0;
foreach(char NumOfChar in ky)
{
charlength ++;
}
GUI.TextArea(new Rect (0,0,charlength*10 + 100,20),"Key is " + ky /*+ " value is " + string.Join(",", vl) + " position is " +int.Parse(indx.ToString())*/);
for (int i = 0; i < dictionary[dictionary.Keys.ElementAt(indx)].Length; i++)
{
if (GUI.Button (new Rect(0, 30 + Screen.height-Screen.height + 40* i, 100, 20),dictionary[dictionary.Keys.ElementAt(indx)][i]))
{
for (int i2 = 0; i2 < dictionary[dictionary.Keys.ElementAt(indx)].Length; i2++)
{
string Answer = dictionary[dictionary.Keys.ElementAt(indx)][i2];
if (Answer.EndsWith("(A)"))
{
print ("Correct");
}
else
{
print ("Incorrect");
}
}
}
}
}
}
I assume you're loading the available answers to the form, maybe in labels with buttons beside them or the text of the button. Either way when you load the answers set the tag property of the correct button with an "A". If the tag of the clicked button has an "A" it's correct.
Changing to something this simple that is easily adapted to the structure you already have, would be much better than trying to make something that is inherently flawed work
In the event handler for the button click something like this should work:
void ButtonClck(object sender, eventargs e)
{
Button clickedbutton = (Button)sender;
if ((string)clickedbutton.Tag = "A")
{
print ("Correct");
}
else
{
print ("Incorrect");
}
}
The way to accomplish this is simply use an if statement following the initial buttion click event . you check if the source where that button gets its text is the correct answer .
if (GUI.Button (new Rect(0, 30 + Screen.height-Screen.height + 40* i, 100, 20),dictionary[dictionary.Keys.ElementAt(indx)][i]))
{
if (dictionary[dictionary.Keys.ElementAt(indx)][i].EndsWith ("(A)"))
{
print ("Correct");
}
else
{
print ("Incorrect");
}
}

How to improve search speed in data grid view

I have a datagridview which contain student details (first name, last name, gender, degree and burn date)
I write this code to perform "keyboard search" (for this example I "load" the data locally):
public class StudentDetails
{
public string firstName;
public string lastName;
public string gender;
public string degree;
public DateTime burnDate;
};
public List<StudentDetails> studentSearchList = new List<StudentDetails>(); // Contain all dgv for searches
private void Form1_Load(object sender, EventArgs e)
{
refreshDataGridView();
}
private void refreshDataGridView()
{
for (int i = 0; i < 1000; i++)
{
StudentDetails sd = new StudentDetails();
sd.firstName = GetRandomFirstName();
sd.lastName = GetRandomLastName();
sd.gender = GetRandomGender();
sd.degree = GetRandomDegree();
sd.burnDate = GetRandomBurnDate();
studentSearchList.Add(sd);
addRowToDataGrid(sd);
}
}
bool detailsContain(StudentDetails sd, string s)
{
if (sd.firstName.ToLower().Contains(s) ||
sd.lastName.ToLower().Contains(s) ||
sd.gender.ToLower().Contains(s) ||
sd.degree.ToLower().Contains(s) ||
sd.burnDate.ToShortDateString().ToString().Contains(s))
return true;
else
return false;
}
void addRowToDataGrid(StudentDetails sd)
{
string[] row = new string[] { sd.firstName, sd.lastName, sd.gender, sd.degree, sd.burnDate.ToShortDateString().ToString() };
dataGridView1.Rows.Add(row);
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
List<StudentDetails> list_SD = new List<StudentDetails>();
String s = textBox1.Text;
s = s.ToLower().Trim();
foreach (StudentDetails sd in studentSearchList)
if (detailsContain(sd, s)) list_SD.Add(sd);
// Clear old rows
dataGridView1.Rows.Clear();
dataGridView1.Refresh();
// Adding the new rows
foreach (StudentDetails sd in list_SD)
addRowToDataGrid(sd);
}
My problem is the searching is too slowly and I have no idea to improve the speed.
I tried to declare another list that contain all database and to fill studentSearchList just with the last search result until the user press on delete character but it's not so help and it's cost memory…
Maybe someone have good search algorithm to suggest ?
Thank you
You need to keep your records "StudentDetails" in the array, not in the list.
Thereafter, build additional index-array (unsigned int or short)
for each searchable field, and sort indices in those arrays according values
of appropriate fields.
Thereafter, you will just use binary search for each necessary field, which is log(N).
You should first measure what takes time. Is it the search itself (I doubt) or refreshing the datagrid on every keystroke ?

Categories