if statements in buttons c# - c#

I'm a brand new n00bie in visual c# and I ran into a weird obstacle that is driving me CRAZY!! Here is the code in question (yes, an Hello World program):
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;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Equals("Goodbye Cruel World"))
{
textBox1.Text = ("Hello World!");
}
else { textBox1.Text = ("Goodye Cruel World"); }
}
}
}
I also tried to use textBox1.Text=="Goodbye Cruel World"; as the evaluation parameter for the if statement getting no errors in the compiler (by the way I am using Visual Studio 2012 Ultimate)
The program runs fine. I initalised the textbox text property as "Hello World!" using the Design GUI of VS. The problem I am facing is that the code works only the first time the user clicks the button. Any time after the button does NOTHING.
I debugged the code and I made sure that the textbox text property is appropriately changed the first time the user clicks the button. When the user clicks the button a second time (or any time after that for that matter) once the code gets to the if statement it skips it, as if the evaluation of the expression within is FALSE. In fact, keeping up with the debug tool, the button keeps executing only the code within the else block, even though I know for a fact that the TextBox.Text property that I am working with has been appropriately changed before.
What am I missing here??? Why doesn't the button just switches the textbox text value between the two strings I hardcoded within?

You are using three strings, not two. "Goodye Cruel World" is not equal to "Goodbye Cruel World". Hence, you cannot expect any kind of "string swapping" behaviour whatsoever from this source code.
Lesson to learn: Do not use the same string at different points of your code. Instead, create a constant string variable which has that value, and then use it every time you need it. For example code see Habib's answer.

That is a case of defining string constant in your code:
public partial class Form1 : Form
{
private const string GOODBYE = "Goodbye Cruel World";
private const string HELLO = "Hello World!";
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Equals(GOODBYE ))
{
textBox1.Text = HELLO;
}
else { textBox1.Text = (GOODBYE ); }
}
}
If you are using same string in multiple places then its better if you define it as a const and use that everywhere in your code, this will help you in reducing errors like the one you have now (Goodye is Goodbye) and it is also easier to change/maintain.

Check the spelling of Goodye in the else clause. The condition will always be false.

Related

Trying to understand C#, WPF and User Input between functions

I am new here as well as to C#. I'm trying to learn it better and as a basic programming challenge for myself, I'm trying to understand how to move or return certain values from user input/text boxes after being submitted to a table that is displayed in a list.
Here is my "challenge" I'm trying to create a simple program that has 2 text boxes one for a name of the new value to a list (not an array I've learned that the hard way) and one for a name of a searched value in a said list. Submit button for each of those text boxes with a message stating either "Value Added" when it was added, or "Found" "Doesn't Exist" for the search button. Then on a side of said boxes and buttons I actually want to display my list with a scrollable 2 column window / box, First column as position in a table like value in which its at and then the actual name of the said value that was added. (Oh an also a clear button for the list itself)
So here is what I've gathered so far. I understand I have to transform all input into a string and then push it to the list. I know how to display the MessageBox.Show("") however I don't know how to code conditions to it. I would try a simple if () but I would first need to be able to program a working search function which requires pushing and pulling data from the list. I know JavaScript has array.push and array.indexof which makes finding and pushing things into an array rather simple, but to my knowledge, C# does not have that function.
I am new to this so any tips on a material to read that would help me learn C# or any tips on how to make this work properly will be appreciated. My biggest struggle is to return a value from the said text box into another private void and using it in my var, in other words pushing the product of a function into another function (like in the example below pushing the Add_Text.Text into the var names = new List<string>(); which is in another void above it. Anyway here is my coding or failed attempt at making this somewhat "work".
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ArrayApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// ARRAY CODING / LIST CODING
public class Values
{
public string Position { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
}
public void App()
{
var names = new List<string>();
}
// BUTTON CLICKS / BUTTON ACTION CODING
private void Add_Button_Click(object sender, RoutedEventArgs e)
{
List_Box.Content = Add_Text.Text;
MessageBox.Show("Value Added");
Add_Text.Clear();
}
private void Search_Button_Click(object sender, RoutedEventArgs e)
{
}
// TEXT BOXES / WHAT BUTTON ACTUALLY INPUTS INTO OUR DISPLAY
private void Add_Text_TextChanged(object sender, TextChangedEventArgs e)
{
}
private void Search_Text_TextChanged(object sender, TextChangedEventArgs e)
{
}
// DISPLAY - List_Box not added yet
}
}
Let's walk through this. As you've already mentioned, you need something to store your data. List is a good idea since you don't know the size.
Currently, you're creating a List of the type string, that would work.
There's actually no need for the Values class because because you can get the index of an item with a function called IndexOf - but later more.
Now, once you show the MessageBox when adding an item, you also have to actually add it to your names list. In order to do so, declare the List in your class and initialize it in your constructor. That way you're able to access if from everywhere in your class.
private List<string> names;
public void MainWindow()
{
InitializeComponent();
names = new List<string>();
}
Adding items can be done with the .Add method, it's pretty straight forward.
private void Add_Button_Click(object sender, RoutedEventArgs e)
{
List_Box.Content = Add_Text.Text;
MessageBox.Show("Value Added");
names.Add(Add_Text.Text); // Adding the content of Add_text.Text
Add_Text.Clear();
}
Searching for an item is pretty easy, too. Just use Contains if you want to know whether the item exists or IndexOf if you want to have the index as well. Note: IndexOf returns -1 if nothing can be found.
private void Search_Button_Click(object sender, RoutedEventArgs e)
{
if(names.Contains( SEARCH_TEXT.TEXT /* or wherever you get your pattern from */ )){
// found, display this in some way
} else {
// not found, display this is some way
}
}
SEARCH_TEXT.TEXT contains the pattern you're looking for. I don't know how you named your control, simply replace it.
That's pretty much it.
So, after doing some reading and also your comments helped a lot, I think I got hang of it and got some basic understanding of C# at least how it works logically. This is the "final" version of the AMAZING program I was trying to create. Thanks for the help everyone!
P.S. The comments are for me to learn and reference in the future when I'm learning C# or forget things :)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
/* QUICK TERMINOLOGY
List = An Array that constantly adjusts its maximum size
names = Our actual "database" or table with our values that we've inputted
List_Box = The display table that is visible on the program itself
var = Variable... You know...
"public" or "private" = Those define whether the function is visible to the rest of the program or other "sheets" in the program
void = Defines whether the return value or the output of a function should be something, void means not specified,
if you want string you put string, if you want an integer you put int... etc etc.
*/
namespace ArrayApp
{
public partial class MainWindow : Window
{
/* Private Function for Creating the List which will be a String
We are using a List instead of an Array as an Array needs
a specific amount of indexes so if we have a specific number of data or
a maximum amount of data that a user can input then array would be used
but since we don't know how many indexes we need a list will automatically
adjust the maximum size of our table to suit our needs. I.e. limitless */
private List<string> names;
public MainWindow()
{
InitializeComponent();
names = new List<string>();
}
/* Class for our Items in our list this is not referring the list above but...
the list that it displays as we have a search on demand
but also allows us to search for specific people in the List (array/table) rather than
display over 100+ people, if our database was to get to that size.
Our class function defines what data can be put into our Display List ( List_Box )
Therefore the index can only be an integer and name can only be a string
more on this later. */
class Items
{
public int Index { get; set; }
public string Name { get; set; }
}
/* The Add Button Function
This button takes the content of the TextBox that is right next to it and
adds it to our list called "names" but does not update our display, instead
it shows us a message stating that the value was added to the list.
If we were using an Array with a limited size, we could use an IF to check
if there is a space available and output a message saying "Full" or "Failed" */
private void Add_Button_Click(object sender, RoutedEventArgs e)
{
names.Add(Add_Text.Text); // Adds the value
Add_Text.Clear(); // Clears the text box
MessageBox.Show("Value Added"); // Displays a message
}
/* Firstly...
* We have an IF function that checks whether "names" contains the content
of the search box, so if its a letter "a", it checks if its in our list.
* It then creates a variable "SearchText" that we can later use that simply
means that instead of writing the whole code we can just refer to it by our new name
* Another variable! This one defines our Index in our list, it takes
our previous variable and looks for it in our list and finds what
the index number of that value is.
* Now, since its Search on demand we essentially have two Lists (arrays) now
that we have the name of the value we looking for in string format,
we also have our index as integer (defined earlier in class). We need to take that data
and add it to our display List and for that we have our function.
Adds new Items to our list using the Items Class and also defines
what data should be put into each column.
* It then clears the search text box
* and shows us that the value has been found.
We then move to ELSE which is simple really...
* Didn't find data
* Clears search text box
* Displays message that its not been found... */
private void Search_Button_Click(object sender, RoutedEventArgs e)
{
if (names.Contains(Search_Text.Text)) // Our If statement
{
var SearchText = Search_Text.Text; // First Variable
var FindIndex = names.IndexOf(SearchText); // Second Variable
List_Box.Items.Add(new Items() { Index = FindIndex, Name = SearchText}); // Adding items to display list
Search_Text.Clear(); // Clear search text box
MessageBox.Show("Data Found"); // Display message
}
else
{
Search_Text.Clear();
MessageBox.Show("Not Found");
};
}
/* Lastly a simple clear button for our display list.
* Once a user searches for many values and wants to clear the display list
* he can do it by hitting a single button.
*
* This button DOES NOT delete anything from our "names" list it only
* clears the display data meaning that the user can search for more data
* that has been added already. */
private void Clear_Button_Click(object sender, RoutedEventArgs e)
{
List_Box.Items.Clear();
}
private void Add_Text_TextChanged(object sender, TextChangedEventArgs e)
{
}
private void Search_Text_TextChanged(object sender, TextChangedEventArgs e)
{
}
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
}
}
Here is how it looks, simple but you get the idea, I'm learning...

Greatest Value in a Dataset

I am attempting to find the greatest value in the highlighted column of this access database. I have tried a few ways of doing it but none of them work.
I need to use LINQ. Preferably the from x in y [...] select x; statement. If I cannot to this with the aforementioned then anything using LINQ would probably suffice. If you could explain why your answer works that would help me out a lot.
Edit:
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;
namespace CarStatistics
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'honestRalphsUsedCarsDataSet.tblCars' table. You can move, or remove it, as needed.
this.tblCarsTableAdapter.Fill(this.honestRalphsUsedCarsDataSet.tblCars);
}
private void btnCarAmount_Click(object sender, EventArgs e)
{
lblCarAmount.Text = "Our inventory consists of " + (dgvCars.RowCount - 1).ToString() + " cars!";
lblCarAmount.Visible = true;
}
private void btnMstExpensive_Click(object sender, EventArgs e)
{
//Code to find Max
}
}
}
The appropriate linq method to use would be [Enumerable.Max][1]. There are many overloads but the ones you will want are either the one that works on an IEnumerable<decimal> (assuming that that type of your column is decimal). This would be used as:
source.Select(x=>x.Price).Max()
source would be the IEnumerable that you have the data in and x.Price assumes that the value of that column is obtainable through a property called Price.
The other alternative would be using the overload of max that takes a Func<TSource, decimal> to tell it what data to use for the max:
source.Max(x=>x.Price)
I'm not sure there is much difference apart from in readability. I'd probably be inclined towards the first, particularly since in the first draft of this question I got wrong what the second actually returns (Thanks to Robert McKee for correcting me on that). :)
Something like this should be what you're looking for:
var maxPrice = db.Items.OrderByDescending(i => i.Value).FirstOrDefault().Value;
This works by ordering all of the rows based on the column specified, then takes the first row from that list, and selects the value of that column.

Listing integers from a text file into a listview

I'm creating an app in winforms c# using vs 2013.
In the app I have a textfile to which I'm saying the time in int format using a custom format from a time select dropdown list.
I then want to display what is in that text file on a selectable listview from where I can remove it from the textfile etc. I'm almost there however at the moment when I try to add the items into the listbox they do seem to add however they do not display correctly.
For example say in my text file there is
22102210
19101610
17182218
10272227
Then that is how it should be displayed in the listview as selectable ready to be deleted.
At the moment it isn't showing correctly, it's showing up as 1.. 2.. 1..
Could someone help me out and point me in the right direction as to why this might be happening? Any help much appreciated. This is my class.
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;
namespace Chronos
{
public partial class Interface : Form
{
private string[] getTimes = System.IO.File.ReadAllLines(#"G:\Dropbox\University\Chronos\Application\Chronos\Chronos\AdminAccount\Times.txt");
public Interface()
{
InitializeComponent();
}
private void Interface_Load(object sender, EventArgs e)
{
PopulateList();
}
private void PopulateList()
{
int size = getTimes.Length;
lstTime.Items.Clear();
GetTimes();
for (int i = 0; i < size; i++)
{
lstTime.Items.Add(getTimes[i]);
}
}
private void GetTimes()
{
string[] getTimes = System.IO.File.ReadAllLines(#"G:\Dropbox\University\Chronos\Application\Chronos\Chronos\AdminAccount\Times.txt");
}
private void btnAdd_Click(object sender, EventArgs e)
{
string time = pickerTimeStart.Value.Hour.ToString() + pickerTimeStart.Value.Minute.ToString() + pickerTimeEnd.Value.Hour.ToString() + pickerTimeEnd.Value.Minute.ToString();
System.IO.File.AppendAllText(#"G:\Dropbox\University\Chronos\Application\Chronos\Chronos\AdminAccount\Times.txt", time + Environment.NewLine);
PopulateList();
MessageBox.Show("Time added", "Ok");
//PopulateList();
}
}
}
As currently written, GetTimes does nothing except read the file:
private void GetTimes()
{
// "string[]" here overrides the outer scope
string[] getTimes = System.IO.File.ReadAllLines(#"G:\Dropbox\University\Chronos\Application\Chronos\Chronos\AdminAccount\Times.txt");
}
If you change it to this, it becomes more useful:
private string[] GetTimes()
{
return File.ReadAllLines(#"G:\Dropbox\University\Chronos\Application\Chronos\Chronos\AdminAccount\Times.txt");
}
... and then PopulateList can simply become:
lstTime.Items.Clear(); //so you aren't getting a bunch of dupes
lstTime.Items.AddRange(GetTimes().Select(t => new ListViewItem(t)).ToArray());
You can also remove this line because you don't need to keep a copy of the data in the class:
private string[] getTimes = ...
Note: If you decide to keep the data source local and not work solely against the file, much of this would change.

Unable to pass a parameter in C#?

Okay. For the iLab my class and I are doing this week, we are working with GUIs. The second program we must design is a guessing game. The program is supposed to randomly generate a number, 0 through 100, and pass that number on to be used later. Here is the code I already have.
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;
namespace Guessing_game
{
public partial class Form1 : Form
{
int target();
public Form1()
{
InitializeComponent();
Random r = new Random();
int target = r.Next(0, 100);
}
private void btnEvaluate_Click(object sender, EventArgs e)
{
if (txtGuess.Text == target)
{
}
}
}
}
}
Mind you, the "btnEvaluate_Click" area is not done. This is because the variable "Target" that should be accessible by the program is unable to be read later on.
After reading through some of the comments, I was able to tweak the code so I get one more error: "Field 'Guessing_game.Form1.target' is never assigned to, and will always have its default value 0" IF anyone is going to try and replicate this, I can tell you exactly how to write it. The GUI should have a label, a text box, and a button. The button needs to get the value given to "target" so it can check the user's guess against target's value. I'm using Visual Studio 2010, if it helps.
Try this, You need to declare target public
Random r = new Random();
int target = r.Next(0, 100);
public Form1()
{
InitializeComponent();
}
private void btnEvaluate_Click(object sender, EventArgs e)
{
if (txtGuess.Text == target)
{
}
}
You have to put int target outside of the public Form(). Inside your event, change target to target.ToString().
The parentheses {} define a scope. You've declared the target variable within the scope of the constructor (Form1). Therefore, in order to make it accessible throughout the class, you can make it a class level variable. For example
int target;
public Form1()
{
InitializeComponent();
Random r = new Random();
target = r.Next(0, 100);
}
(Although if you plan to use the Random object again, you'd want to make that a class level variable as well). Also, you're trying to compare an int to a string. It should be
if (txtGuess.Text == target.ToString())
{
}
That's because target is local to the constructor and therefore can't be seen anywhere else. Make target a field in Form1 instead. Because this is homework, I'll let you try that out on your own; let us know if you're still stumped.

Threading and GUI elements in C#

i am trying to make a basic IRC client...but my problem is getting the text to display in a RTF box without it lagging
i settled on using threading, and i want to update the RTF box in a thread, but i cant because it gives me errors about the RTF box element not being static?
any insight? i will paste code if you guys want it
ok here is the code (do edits bump?)
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.Net.Sockets;
using System.IO;
using System.Threading;
using System.Net;
namespace IrcClient
{
public partial class mainWindow : Form
{
static IRC client;
static string newLine, oldLine;
public mainWindow()
{
InitializeComponent();
}
private void main()
{
}
private void mainWindow_Load(object sender, EventArgs e)
{
client = new IRC("irc.freenode.net" ,6667, "jimi__hendrix");
new Thread(new ThreadStart(update)).Start();
}
private static void update()
{
newLine = client.sr.ReadLine();
Thread.Sleep(50);
}
private void btnSend_Click(object sender, EventArgs e)
{
client.privmsg(inputBox.Text);
messageBox.AppendText(inputBox.Text + "\n");
inputBox.Text = "";
}
private void timer1_Tick(object sender, EventArgs e)
{
if (newLine != oldLine)
{
messageBox.AppendText(newLine + "\n");
oldLine = newLine;
}
}
}
class IRC
{
TcpClient connection;
NetworkStream stream;
public StreamWriter sw;
public StreamReader sr;
string nick;
public IRC(string server, int port, string Nick)
{
try
{
connection = new TcpClient(server, port);
stream = connection.GetStream();
sr = new StreamReader(stream);
sw = new StreamWriter(stream);
nick = Nick;
sw.WriteLine("PASS " + "caruso11");
sw.Flush();
sw.WriteLine("NICK " + nick);
sw.Flush();
sw.WriteLine("USER Jimi__Hendrix 8 irc.freenode.net :Jimi__Hendrix");
sw.Flush();
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
public void privmsg(string msg)
{
sw.WriteLine(msg);
sw.Flush();
}
public void parse(string msg)
{
}
}
}
some of the methods are blank and some code could be cleaned up, but i want to get this done first...also, theres the code generated by visual studios that sets up the window
In general, trying to update a Control from a thread other than the main thread will not work, due to limitations of Windows. If you need to call a method or set a property on the RTF box from your worker thread, you'll probably need to use Invoke or BeginInvoke. This might look like the following:
void MyThreadMethod()
{
// stuff
this.rtfBox.BeginInvoke( (MethodInvoker)(()=> this.rtfBox.Text = "foo") );
// stuff
}
Edit: As others point out, if this is actually failing to compile due to an error about the control not being static, you're probably trying to reference a member variable from a static function, which is illegal. Posting code will help narrow down the problem.
I believe you are using Windows Forms. Check out this text about it, there is some remarks that you have to take care before making a thread accessing forms elements directly.
If this is not exactly your problem, please elaborate more the question.
RULE: You should not access one window from another thread.
Use this technique:
from your thread raise an event to update the RTF (with required text etc data)
on the GUI thread use the following:
use the "InvokeRequired" property to verify call is from GUI thread or not
Use the Invoke method (you will need a delegate for this)
BeginInvoke also works but the only problem is it does not really guarantee immediate start (it uses threadpool). I prefer to use the Invoke method instead.
Others have already mentioned what the problem you are experienced is, and how to solve it.
Not that having a separate worker thread is a bad idea, it seems odd that you need multiple threads because of performance reasons. It seems that for as something as simple as an IRC client, you should be able to do everything on one thread without any UI sluggishness. Maybe you can post some code so that we can see what the root of the problem is?
The RichTextBox is on the UI thread so you're not going to be able to access the RichTextBox unless your on the UI thread. How are you loading the content? How big is the content? Is the lag coming from loading the content or the RTF box parsing it?
You're probably referencing a member variable of the form, instead of a static variable, thus the error.
Anyway this is quite a wrong approach, since UI elements can only be updated from the UI thread, otherwise you'll get a cross-thread operation exception. So you'll need to do Invoke() to the set-text method on the UI thread, which will eventually 'lag' too.
Not sure what you mean by 'lagging', you may try making your parent form double-buffered to reduce flicker.

Categories