how to stop text changed texbox from runing contains text code? - c#

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

Related

Need to sort words in an array using a separate method

Question:
Write a program named SortWords that includes a method that accepts any number of words and sorts them in alphabetical order. Demonstrate that the program works correctly when the method is called with one, two, five, or ten words.
What I have thus far:
private void button1_Click(object sender, EventArgs e)
{
String[] outWords = new string[20];
outWords[0] = textbox1.Text;
outWords[1] = textBox2.Text;
outWords[2] = textBox3.Text;
outWords[3] = textBox4.Text;
outWords[4] = textBox5.Text;
outWords[5] = textBox6.Text;
outWords[6] = textBox7.Text;
outWords[7] = textBox8.Text;
outWords[8] = textBox9.Text;
outWords[9] = textBox10.Text;
sortAndPrint(outWords[11]);
}
private void sortAndPrint(params string[] newWords)
{
Array.Sort(newWords);
label1.Text = newWords[0];
label2.Text = newWords[1];
label3.Text = newWords[2];
label4.Text = newWords[3];
label5.Text = newWords[4];
label6.Text = newWords[5];
label7.Text = newWords[6];
label8.Text = newWords[7];
label9.Text = newWords[8];
label10.Text = newWords[9];
}
My issues here is that I either don't get anything in my label boxes or I get errors thrown from can't convert a string into string[] or System.IndexOutOfRangeException. I'm sure im doing something completely wrong here.
Try this :
private void button1_Click(object sender, EventArgs e)
{
string[] outWords = new string[10];
outWords[0] = textbox1.Text;
outWords[1] = textBox2.Text;
outWords[2] = textBox3.Text;
outWords[3] = textBox4.Text;
outWords[4] = textBox5.Text;
outWords[5] = textBox6.Text;
outWords[6] = textBox7.Text;
outWords[7] = textBox8.Text;
outWords[8] = textBox9.Text;
outWords[9] = textBox10.Text;
sortAndPrint(outWords);
}
private void sortAndPrint(string[] newWords)
{
Array.Sort(newWords);
label1.Text = newWords[0];
label2.Text = newWords[1];
label3.Text = newWords[2];
label4.Text = newWords[3];
label5.Text = newWords[4];
label6.Text = newWords[5];
label7.Text = newWords[6];
label8.Text = newWords[7];
label9.Text = newWords[8];
label10.Text = newWords[9];
}
Summary
Pass whole array sortAndPrint(outWords); not single element.
Take array length only what you need. string[] outWords = new string[10];
Please check this question for the use of params. You need to pass values when you user param but if you need to pass variable, you have to remove params.
Example of params
private void button1_Click(object sender, EventArgs e)
{
sortAndPrint("one","two","three","four","five");
}
private void sortAndPrint(params string[] newWords)
{
Array.Sort(newWords);
label1.Text = newWords[0];
label2.Text = newWords[1];
label3.Text = newWords[2];
label4.Text = newWords[3];
label5.Text = newWords[4];
}
sortAndPrint(outWords[11]);
will pass a single string (as an array) to sortAndPrint, so when you call
label2.Text = newWords[1];
you get an out of bounds exception. Try just
sortAndPrint(outWords);
to pass the entire array. Also note that empty slots in the array wil get sorted before other strings, so you need to come up with a way to get rid of the blank/null string.
Or, if the intent is to demonstrate how to use params, you could do something like:
sortAndPrint(textbox1.Text,
textbox2.Text,
textbox3.Text,
textbox4.Text,
textbox5.Text);
But you need to check the bounds of the array in sortAndPrint, rather than just assuming the array has a size of at least 10.
If you read the instructions carefully, you have this requirement:
...includes a method that accepts any number of words...
You accomplish this by using the params keyword along with a string[].
...and sorts them in alphabetical order.
This part you doing with Array.Sort(newWords);
Demonstrate that the program works correctly when the method is called with one, two, five, or ten words
This part you're not doing - you're assuming in your code that the input array will have 10 items, when instead you should check to see how many items it has before outputting the results.
Since the array size cannot be determined by the method, then it cannot make any assumption that there will be enough labels on the form to populate with the results. Given this, we could use a MessageBox to show the results instead, and we can use String.Join to join all the items in the array with an Environment.NewLine character in order to show the sorted words in different lines:
private void SortAndPrint(params string[] newWords)
{
Array.Sort(newWords);
MessageBox.Show(string.Join(Environment.NewLine, newWords));
}
Now, we can demonstrate the use of this function by passing in different numbers of arguments to it.
First, just so we're on the same page, I have this code in the Form_Load method that adds 10 textboxes to the form, all with the tag "input":
private void Form1_Load(object sender, EventArgs e)
{
var stdHeight = 20;
var stdWidth = 100;
var stdPad = 10;
var count = 10;
for (int i = 0; i < count; i++)
{
var textBox = new TextBox
{
Name = "textBox" + (i + 1),
Left = stdPad,
Width = stdWidth,
Height = stdHeight,
Top = (stdHeight + stdPad) * i + stdPad,
Tag = "input"
};
Controls.Add(textBox);
}
}
Now, in our button click event, we can search for all controls on the form who have the Tag == "input" and whose .Text property is not empty, and we can pass these Text values to our method both as a single array OR as individual items:
private void button1_Click(object sender, EventArgs e)
{
// Select all textbox Text fields that have some value
var words = Controls.Cast<Control>()
.Where(t => t.Tag == "input" && !string.IsNullOrWhiteSpace(t.Text))
.Select(t => t.Text)
.ToArray();
// Pass all the words in a single array to our method
SortAndPrint(words);
// We can also demonstrate this by passing individual words
// Pass one word if we can
if (words.Length > 0)
{
SortAndPrint(words[0]);
}
// Pass two words if we can
if (words.Length > 1)
{
SortAndPrint(words[0], words[1]);
}
// Pass five words if we can
if (words.Length > 4)
{
SortAndPrint(words[0], words[1], words[2], words[3], words[4]);
}
// Pass ten words if we can
if (words.Length > 9)
{
SortAndPrint(words[0], words[1], words[2], words[3], words[4],
words[5], words[6], words[7], words[8], words[9]);
}
}

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();

Conversion program storing information in array and using a combobox

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

Append an item to an existing list

I am working with a link list. I have set my constructor to take an array named ax with a set of already defined items. I also decided to have an input box which through a BtnAddTree_Click appends the new item to the list ax. But instead of appending to the list ax it creates a whole new separate list. How can I append items to the array list ax through my AddTree function?
public ListForTrees(IEnumerable<fruit_trees> trees)
{
foreach (fruit_trees t in trees)
{
this.AddTree(t);
}
}
public void AddTree(fruit_trees new_tree)
{
fruit_trees current = first_tree;
if (count == 0)
{
first_tree = new_tree;
last_tree = new_tree;
count = 1;
}
else if (count != 0)
{
if (new_tree.tree_price <= first_tree.tree_price)
{
new_tree.next_tree = first_tree;
first_tree = new_tree;
}
else if (new_tree.tree_price >= last_tree.tree_price)
{
last_tree.next_tree = new_tree;
last_tree = new_tree;
}
else
{
while (new_tree.tree_price > current.next_tree.tree_price)
{
current = current.next_tree;
}
new_tree.next_tree = current.next_tree;
current.next_tree = new_tree;
}
count++;
}
}
}
ListForTrees mainlist = new ListForTrees();
private void BtnGo_Click(object sender, EventArgs e)
{
fruit_trees[] ax = { new fruit_trees("cherry", 48, 12.95, 3),
new fruit_trees("pine", 36, 9.95, 8),
new fruit_trees("oak", 60, 14.95, 2),
new fruit_trees("peach", 54, 19.95, 3),
new fruit_trees("pear", 36, 11.85, 2),
new fruit_trees("apple", 62, 13.45, 5)
};
mainlist = new ListForTrees(ax);
fruit_trees current = mainlist.first_tree;
while (current != null)
{
current = current.next_tree;
}
}
}
}
It doesn't seem to be creating a new separate list. I tested out the following code with yours:
public class TreeTester
{
public static void Main(string[] args)
{
var list = new ListForTrees(
new[] { new fruit_trees("tree10",10,10,10), new fruit_trees("tree2",2,2,2) });
list.AddTree( new fruit_trees("tree3",3,3,3) ); // middle
list.AddTree( new fruit_trees("tree1",1,1,1) ); // first
list.AddTree( new fruit_trees("tree50",50,50,50) ); // last
list.AddTree( new fruit_trees("tree5",5,5,5) ); // middle
Console.Write(list);
}
}
And got the following output, which seems correct.
tree1 1 1 1
tree2 2 2 2
tree3 3 3 3
tree5 5 5 5
tree10 10 10 10
tree50 50 50 50
What is the expected behavior, if this is not correct? Clearly these items are all being added to the original list, since they're present when I iterate through the list.
By the way, I also added the following ToString function to your ListForTrees class; it makes debugging easier.
public override string ToString()
{
string s = "";
for (var tree=first_tree; tree!=null; tree = tree.next_tree)
s += tree + "\n";
return s;
}
Edit: I must comment that you may find it helpful to cleanup your code a bit in trying to understand where it is going wrong. For example, your ListForTrees(fruit_trees new_tree) constructor does the same exact thing as calling Add(new_tree) would. Also, think about three cases you have in Add, under else if (count != 0) -- perhaps there's a way they could elegantly combined into one general while loop? It makes it easier to analyze, and (potentially) less error-prone.

Display strings from a list one by one into a label

I have a label. I have a list. when I do "label1.Text = match.Value;", it just displays the last item of the list, as opposed to 1 string that changes each time I click a button. The code is:
private void frontPageToolStripMenuItem_Click(object sender, EventArgs e)
{
const string url = "http://reddit.com/r/pics";
var source = getSource(url);
var regex = new Regex([regex removed]);
var links = new List<string>();
var titles = new List<string>();
foreach (Match match in regex.Matches(source))
{
links.Add(match.Groups[1].Value);
titles.Add(match.Groups[2].Value);
}
foreach (var title in titles)
{
label1.Text = title; /*it just shows the last 'title' in 'titles', I want it to start at the first, and go to the next title every time the event occurs (frontPageToolStripMenuItem_Click)*/
}
}
Thanks in advance!
You need to initialize the list outside of your click event handler. You could create an FetchImageData method that is called when your program starts (perhaps call it from the constructor of your class). Or you could call it the list the first time the click event is fired.
private int clickCounter = 0;
private List<string> links;
private List<string> titles;
private void FetchImageData()
{
links = new List<string>();
titles = new List<string>();
const string url = "http://reddit.com/r/pics";
var source = getSource(url);
var regex = new Regex([regex removed]);
foreach (Match match in regex.Matches(source))
{
links.Add(match.Groups[1].Value);
titles.Add(match.Groups[2].Value);
}
}
You haven't said what should happen when the user clicks more times than there are elements. One option is to wrap around and starts again from the beginning. This can be achieved using the % operator.
private void frontPageToolStripMenuItem_Click(object sender, EventArgs e)
{
if (titles == null) { FetchImageData(); }
label1.Text = titles[clickCounter % titles.Count];
clickCounter++;
}
UI thread doesn't get a chance to update the label because your for loop is on the UI thread. Even if you move the for loop to a background thread good chance you 'll only see some flickering and then the final string. Just append the strings to a textbox or output them using Debug.writeLine. This will show you that you are reading the correct strings.
To change the label just once don't do it in a for loop
1) titles should be global variable
2) Move this in the constructor of the form
const string url = "http://reddit.com/r/pics";
var source = getSource(url);
var regex = new Regex("<a class=\"title \" href=\"(.*?)\" >(.*?)<");
titles = new List<string>();
foreach (Match match in regex.Matches(source))
{
links.Add(match.Groups[1].Value);
titles.Add(match.Groups[2].Value);
}
label1.Text = first value of the titles
3) Your event handler should be like this:
private void frontPageToolStripMenuItem_Click(object sender, EventArgs e)
{
label1.Text = next value of the titles variable;
}
In Second foreach loop put label1.Text += title; instead of label1.Text = title; then it will work fine.

Categories