Creating a search function in c#, windows form application - c#

I am creating a program as part of a college assignment and must have a database connected to my program. The program is in c# and created in a windows form application with visual studio.
I need to have a text box that allows entry and then a button to search for any values that match that, but I cannot figure out how to read what is inputted, search the database and return them in the text boxes.
I already have the database connected and all of the forms designed and connected together with buttons, however this one part is really baffling me. Any help would be appreciated.P.S I am new to c# and do not fully understand it yet.

Please Take Reference from this link your Answer(along with Database Queries) and Explanation is available
Reference 1
Reference 2

1) Put all the texts from the database in some kind of collection (List for example).
2) Get the text from the textbox by accessing the textbox's Text property. Apply some modifications if you want, such as removing caps, handling keywords etc.
3) Write a linq query that goes something like collection.Where(t => t.Contains(searchString)).ToList(). Alternatively, you can loop over the collection.
4) Feed the resulting list to your output textbox.

In my case, I was used a dataGridView for the DataSet of mysql data and below is the sample code for searchbox.
private void tfSearch_TextChanged(object sender, EventArgs e)
{
if(string.IsNullOrEmpty(tfSearch.Text) == false)
{
dataGridView1.Rows.Clear();
for(int i = 0; i < GlobalState.Items.Tables[0].Rows.Count; i++)
{
string id = GlobalState.Items.Tables[0].Rows[i].ItemArray.GetValue(0).ToString();
string name = GlobalState.Items.Tables[0].Rows[i].ItemArray.GetValue(1).ToString();
string price = GlobalState.Items.Tables[0].Rows[i].ItemArray.GetValue(2).ToString();
string stock = GlobalState.Items.Tables[0].Rows[i].ItemArray.GetValue(3).ToString();
if (name.StartsWith(tfSearch.Text))
{
int index = dataGridView1.Rows.Add();
dataGridView1.Rows[index].Cells[0].Value = id;
dataGridView1.Rows[index].Cells[1].Value = name;
dataGridView1.Rows[index].Cells[2].Value = price;
dataGridView1.Rows[index].Cells[3].Value = stock;
}
}
}
else if(tfSearch.Text == "")
{
dataGridView1.Rows.Clear();
for (int i = 0; i < GlobalState.Items.Tables[0].Rows.Count; i++)
{
string id = GlobalState.Items.Tables[0].Rows[i].ItemArray.GetValue(0).ToString();
string name = GlobalState.Items.Tables[0].Rows[i].ItemArray.GetValue(1).ToString();
string price = GlobalState.Items.Tables[0].Rows[i].ItemArray.GetValue(2).ToString();
string stock = GlobalState.Items.Tables[0].Rows[i].ItemArray.GetValue(3).ToString();
int index = dataGridView1.Rows.Add();
dataGridView1.Rows[index].Cells[0].Value = id;
dataGridView1.Rows[index].Cells[1].Value = name;
dataGridView1.Rows[index].Cells[2].Value = price;
dataGridView1.Rows[index].Cells[3].Value = stock;
}
}
Your Welcome.

Get the textbox text when you click on the button then start a query with that search word so youll get back everything what contains that word
Get input text
Textboxname.text;
Query
SELECT * ON table WHERE tagoridorwhatever = textboxname.text
The query part may be a bit different since im weiting this out of my head on a mobile phone

Related

C# Checking textbox text is the same as values from database stored in the list

I know why I am getting this error, but I do not know a way around it.
I am trying to check if the answers the user types into the textbox is correct.
I will do this by checking the answer against the answer in the database.
I have stored the contents from the database into a list so I can compare the users answer against the correct answer.
{
string mydbConnection = "datasource=localhost;port=3306;Initial Catalog=project;username=xxx;password=xxx;";
MySqlConnection connDB = new MySqlConnection(mydbConnection);
MySqlCommand cmdDataBase = new MySqlCommand("SELECT questions.answer FROM questions;", connDB);
MySqlDataReader DBReader;
connDB.Open();
DBReader = cmdDataBase.ExecuteReader();
while (DBReader.Read())
{
List<string> answers = new List<string>();
for (int i = 0; i < DBReader.FieldCount; i++)
answers.Add(DBReader.GetValue(i).ToString());
for (int i = 0; i < answers.Count; i++)
{
if (answers[i].Contains(textBoxQ1, textBoxQ2, textBoxQ3, textBoxQ4, textBoxQ5, textBoxQ6, textBoxQ7, textBoxQ8, textBoxQ9, textBoxQ10))
{
label1.Text = "Well done, Correct Answer";
}
else
{
label1.Text = "unlucky, wrong answer";
}
}
}
}
I am getting the error:
No overload for method 'Contains' takes 10 arguments
I know why I am getting the error. I think it is because the method 'contains' can only take 1 parameter. However I do not know how a way around this. My question is HOW can I amend by code to achieve this objective?
EDIT:
When you retrieve the questions from the database, for each question you retrieve the question text and the questionID.
Later on, use the questionID to get the correct answer for that individual question. For example when you have question with questionid 42, you can get the correct answer for that question via
select answer from questions where questionID = 42;
Now perform the following in your application:
For each answer entered by the user, retrieve the questionID from the grid. Then retrieve the correct answer for that question from the database via the statement shown above. Then compare that answer with the answer entered by user in the corresponding TextBox.
Another alternative is that you already get the correct answers from the database when populating the questions and store the answer in a hidden column in the DataGridView. Then you do not even have to go to the database again to check the answers, but can just compare the answer given by the user to the answer already stored in the DataGridView.
Some sample code for this second approach, not using a database, but initializing the datagrid manually.
private void Form1_Load(object sender, EventArgs e)
{
// Fill data grid
DataTable dataTable = new DataTable();
dataTable.Columns.Add("QuestionID");
dataTable.Columns.Add("Question");
dataTable.Columns.Add("Answer");
dataTable.Rows.Add(1, "5 + 4", "9");
dataTable.Rows.Add(2, "Capital of Germany", "Berlin");
dataTable.Rows.Add(23, "Angela ...", "Merkel");
dataTable.Rows.Add(42, "Capital of France", "Paris");
dataGridViewQuiz.DataSource = dataTable;
// Hide id and answer
dataGridViewQuiz.Columns["QuestionID"].Visible = false;
dataGridViewQuiz.Columns["Answer"].Visible = false;
}
// function to check an individual answer from a given TextBox
// against a given row in the datagrid.
private bool CheckAnswer(DataGridViewRow dataGridViewRow, TextBox textBox)
{
string correctAnswer = dataGridViewRow.Cells["Answer"].Value.ToString();
string givenAnswer = textBox.Text;
bool isCorrect = string.Equals(correctAnswer, givenAnswer, StringComparison.CurrentCultureIgnoreCase);
return isCorrect;
}
private void buttonCheck_Click(object sender, EventArgs e)
{
bool firstAnswerCorrect = CheckAnswer(dataGridViewQuiz.Rows[0], textBoxQ1);
bool secondAnswerCorrect = CheckAnswer(dataGridViewQuiz.Rows[1], textBoxQ2);
bool thirdAnswerCorrect = CheckAnswer(dataGridViewQuiz.Rows[2], textBoxQ3);
bool fourthAnswerCorrect = CheckAnswer(dataGridViewQuiz.Rows[3], textBoxQ4);
}
If u want to check if multiple conditions are being meet you could use a and.

How to display data from mysql and display it one by one?

I have a data in mysql and I want to display the data one by one everytime I click the button. How to do it?
string ConnectToServer = #"server=..*.;port=****; user id=sampleID; password=samplePW; database=sampleDB; pooling=false";
public void GetNames()
{
MySqlConnection NameConnector = null;
MySqlDataReader NameReader = null;
try
{
NameConnector = new MySqlConnection(ConnectToServer);
NameConnector.Open();
string Name = "SELECT * from sampleNames";
MySqlCommand NameCommand = new MySqlCommand(Name, NameConnector);
NameReader = NameCommand.ExecuteReader();
while (NameReader.Read())
{
Console.WriteLine(NameReader.GetInt32(0) + ": " + NameReader.GetString(1));
NameLabel.Text += NameReader.GetString("Names") + "\n";
}
}
catch (MySqlException NameException)
{
Console.WriteLine("error : (0)", NameException.ToString());
}
finally
{
if (NameReader != null)
{
NameReader.Close();
}
if (NameConnector != null)
{
NameConnector.Close();
}
}
}
private void ButtonName_Click(object sender, EventArgs e)
{
GetNames();
}
the output:
Name1
Name2
Name3
Name4
Name5
but I wan't is, the Name will appear one by one each time I click the button
like this:
click = output Name1
click = output Name2
click = output Name3
click = output Name4
click = output Name5
There are at least 2 ways of doing that depending on how real-time you need the data and how many DB calls do you want to make. here they are:
Option #1
Initialize a class level variable for names list and an index variable.
List<string> names = null;
int currentNameIndex = 0;
on the click handler, if names is null, populate the names variable with all names in the DB. display the first item as follows.
private void ButtonName_Click(object sender, EventArgs e)
{
if (names == null)
{
names = GetNames();
}
if (currentNameIndex < names.Count)
{
NameLabel.Text += names[currentNameIndex++];
}
}
the getnames need to be modified to return the list of names.
Option #2
Instead of retrieving the whole list in 1 DB call, you could change the SQL query to get the first record from the Table. (based on a Id or some key)
On a click, GetNames will retrieve only 1 record and display that.
On the next click it'll retrieve another record, but not the first ones.
This would typically involve a query involving a key column. Please post your table schema and I can answer with the Query.
an e.g. Query is
int currentNameId = -1; // class level variable.
query is
Select TOP 1 nameId, names from SampleNames Where NameId > currentNameId Order By NameId;
currentNameId = int.Parse(NameReader[nameId].ToString());
the above query assumes that nameId is a unique key and that values start from 0 or greater than -1, and that they are incremental. (identity PKs etc.)
as I mentioned, if you can provide the table structure, we can answer better.
Option #1 is efficient in DB calls but may potentially have stale data.
Option #2 is more chatty but has more real-time data than Option #1.
You are reading all records:
while (NameReader.Read())
If you want to read just one, try put all your connection outside the method and run
NameReader = NameCommand.ExecuteReader();
only once.
Then change
while (NameReader.Read())
to
NameReader.Read()

Need to populate several labels from XML file, is there a faster way?

I have an XML file I am loading and breaking the document down into Ienumerable then putting each element into a label on a winform. sofar I have the following code, which works
public void PopulateGameBoard()
{
XDocument gameFiles = XDocument.Parse(Properties.Resources.Jeopardy);
IEnumerable<string> categories =
from category in gameFiles.Descendants("category")
select (string)category.Attribute("name");
string first = categories.ElementAt(0);
cat1HeaderLabel.Text = first;
string second = categories.ElementAt(1);
cat2HeaderLabel.Text = second;
string third = categories.ElementAt(2);
cat3Label.Text = third;
string fourth = categories.ElementAt(3);
cat4Label.Text = fourth;
string fifth = categories.ElementAt(4);
cat5Label.Text = fifth;
}
The final product is Jeopardy Game Board where the categories and questions will be pulled from an XML file
This is the first of 5 rows that I will need to do this with (5 lists going into 5 rows). I am wondering if there is a better way to code this where I dont end up with 25 statements assigning a variabel to an ElementAt() and then 25 assignments of that variable.
Here I tried to create labels dynamically and assign values to them,This is a hand written code,so no guarentee it will compile ,make necessary changes
public void PopulateGameBoard()
{
XDocument gameFiles = XDocument.Parse(Properties.Resources.Jeopardy);
IEnumerable<string> categories =
from category in gameFiles.Descendants("category")
select (string)category.Attribute("name");
Label[] cat1HeaderLabel= new Label[100];
int i = 0;
categories.Each(p =>
{
cat1HeaderLabel[i] = new Label();
cat1HeaderLabel[i].Text = p;
this.Form.Controls.Add(cat1HeaderLabel[i]);
i++;
});
}

Why am I getting index out of bounds error from database

I know what index out of bounds is all about. When I debug I see why as well. basically what is happening is I do a filter on my database to look for records that are potential/pending. I then gather a array of those numbers send them off to another server to check to see if those numbers have been upgraded to a sale. If it has been upgraded to a sale the server responds back with the new Sales Order ID and my old Pending Sales Order ID (SourceID). I then do a for loop on that list to filter it down that specific SourceID and update the SourceID to be the Sales Order ID and change a couple of other values. Problem is is that when I use that filter on the very first one it throws a index out of bounds error. I check the results returned by the filter and it says 0. Which i find kind of strange because I took the sales order number from the list so it should be there. So i dont know what the deal is. Here is the code in question that throws the error. And it doesn't do it all the time. Like I just ran the code this morning and it didn't throw the error. But last night it did before I went home.
filter.RowFilter = string.Format("Stage = '{0}'", Potential.PotentialSale);
if (filter.Count > 0)
{
var Soids = new int[filter.Count];
Console.Write("Searching for Soids - (");
for (int i = 0; i < filter.Count; i++)
{
Console.Write(filter[i][1].ToString() + ",");
Soids[i] = (int)filter[i][1];
}
Console.WriteLine(")");
var pendingRecords = Server.GetSoldRecords(Soids);
var updateRecords = new NameValueCollection();
for (int i = 0; i < pendingRecords.Length; i++)
{
filter.RowFilter = "Soid = " + pendingRecords[i][1];
filter[0].Row["Soid"] = pendingRecords[i][0];
filter[0].Row["SourceId"] = pendingRecords[i][1];
filter[0].Row["Stage"] = Potential.ClosedWon;
var potentialXML = Potential.GetUpdatePotentialXML(filter[0].Row["Soid"].ToString(), filter[0].Row["Stage"].ToString());
updateRecords.Add(filter[0].Row["ZohoID"].ToString(), potentialXML);
}
if i'm counting right line 17 is the error where the error is thrown. pendingRecords is a object[][] array. pendingRecords[i] is the individual records. pendingRecords[i][0] is the new Sales OrderID (SOID) and pendingRecords[i][1] is the old SOID (now the SourceID)
Any help on this one? is it because i'm changing the SOID to the new SOID, and the filter auto updates itself? I just don't know
Well I ended up changing how it worked all together and it actually sorts it a bit nicer now. The code i am about to post has a bunch of hard coded numbers due to the structure of my table that is returned. Sorry about that. I have learned since then to not do that, but i am working on a different project now and will change that when I have to change the program. But here is the solution.
var potentials = Server.GetNewPotentials(); //loads all records from server
for (int i = 0; i < potentials.Length; i++)
{
var filter = AllPotentials.DefaultView;
var result1 = CheckSoidOrSource(potentials[i].Soid, true);
var result2 = CheckSoidOrSource(potentials[i].SourceID,false) ;
//This potential can't be found at all so let's add it to our table
if (result1+result2==0)
{
Logger.WriteLine("Found new record. Adding it to DataTable and sending it to Zoho");
AllPotentials.Add(potentials[i]);
filter.RowFilter = string.Format("Soid = '{0}'", potentials[i].SourceID);
var index = AllPotentials.Rows.IndexOf(filter[0].Row);
ZohoPoster posterInsert = new ZohoPoster(Zoho.Fields.Potentials, Zoho.Calls.insertRecords);
AllPotentials.Rows[index]["ZohoID"] = posterInsert.PostNewPotentialRecord(3, filter[0].Row);
}
//This potential is not found, but has a SourceId that matches a Soid of another record.
if (result1==0 && result2 == 1)
{
Logger.WriteLine("Found a record that needs to be updated on Zoho");
ZohoPoster posterUpdate = new ZohoPoster(Zoho.Fields.Potentials, Zoho.Calls.updateRecords);
filter.RowFilter = string.Format("Soid = '{0}'", potentials[i].SourceID);
var index = AllPotentials.Rows.IndexOf(filter[0].Row);
AllPotentials.Rows[index]["Soid"] = potentials[i].Soid;
AllPotentials.Rows[index]["SourceId"] = potentials[i].SourceID;
AllPotentials.Rows[index]["PotentialStage"] = potentials[i].PotentialStage;
AllPotentials.Rows[index]["UpdateRecord"] = true;
AllPotentials.Rows[index]["Amount"] = potentials[i].Amount;
AllPotentials.Rows[index]["ZohoID"] = posterUpdate.UpdatePotentialRecord(3, filter[0].Row);
}
}
AllPotentials.AcceptChanges();
}
private int CheckSoidOrSource(string Soid, bool checkSource)
{
var filter = AllPotentials.DefaultView;
if (checkSource)
filter.RowFilter = string.Format("Soid = '{0}' OR SourceId = '{1}'",Soid, Soid);
else
filter.RowFilter = string.Format("Soid = '{0}'", Soid);
return filter.Count;
}
basically what is happening is that i noticed something about my data when I filter it this way. The two results would only return the following results (0,0) (0,1) and (1,0) (0,0) means that the record doesn't exist at all in this table so I need to add it. (1,0) means that the Sales Order ID (Soid) matches another Soid in the table so it already exists. Lastly (0,1) means that the Soid doesn't exist in this table but i found a record that has the Soid as it's source...which to me means that the one that had it as a source has been upgraded from a potential to a sale, which in turn means i have to update the record and Zoho. This worked out to much less work for me because now I don't have to search for won and lost records, i only have to search for lost records. less code same results is always a good thing :)

Adding a List to a TableLayoutPanel through a Loop

I have a file that stores flight information and then I have a search form that allows a user to select a starting city and state, destination city and state, the departure date and number of seats they want to book.
I then have the results of the matched flights getting printed into a TableLayoutPanel. My issue is that when the program loops through to find the flights, it adds them, but if it finds multiple flights, the previous indexes are all replaced with the current one. Here is my code that searches through the flights (the lists are all label lists):
private void searchFlights()
{
StreamReader sr = File.OpenText("F:\\C#\\Airline\\Flight.txt");
string read = null;
Button button = new Button();
button.Text = "Book";
totalSeats = int.Parse(peopleSearchComboBox.Text);
while ((read = sr.ReadLine()) != null)
{
String[] flights = read.Split(' ');
testSeats = int.Parse(flights[6]);
if (cityStartSearchTextBox.Text == flights[2] & stateStartComboBox.Text == flights[3] & cityDestinationSearchTextBox.Text == flights[4] &
stateDestComboBox.Text == flights[5] & dateSearchTextBox.Text == flights[7] & totalSeats <= testSeats)
{
airlineSearchLabel.Text = flights[0];
priceSearchLabel.Text = flights[1];
seatSearchLabel.Text = flights[6];
startCityLabel.Text = flights[2];
startStateLabel.Text = flights[3];
endCityLabel.Text = flights[4];
endStateLabel.Text = flights[5];
price.Add(priceSearchLabel);
airline.Add(airlineSearchLabel);
seatsMatch.Add(seatSearchLabel);
buttons.Add(button);
cityStartMatch.Add(startCityLabel);
stateStartMatch.Add(startStateLabel);
cityDestMatch.Add(endCityLabel);
stateDestMatch.Add(endStateLabel);
flightsMatched++;
Console.WriteLine(airline[0].Text); //I have this to check the index and on each pass through its different
}
}
sr.Close();
}
And here is my code for printing it to the table:
private void fillTable()
{
blankTableLabel.Text = "";
priceTableLabel.Text = "Price";
seatsTableLabel.Text = "Open Seats";
airlineTableLabel.Text = "Airline";
noMatchedFlightsLabel.Text = "No Matches Found";
flightsSearchedTable.RowCount = flightsMatched + 1;
flightsSearchedTable.Controls.Add(blankTableLabel,0,0);
flightsSearchedTable.Controls.Add(priceTableLabel,1,0);
flightsSearchedTable.Controls.Add(airlineTableLabel,2,0);
flightsSearchedTable.Controls.Add(seatsTableLabel,3,0);
if (AppendTexts.totalFlights != 0 & flightsMatched != 0)
{
for (int x = 0; x < flightsMatched; x++)
{
if (WelcomeScreen.memberLoggedInCheck == true)
{
flightsSearchedTable.Controls.Add(buttons[x]);
flightsSearchedTable.Controls.Add(price[x]);
flightsSearchedTable.Controls.Add(airline[x]);
flightsSearchedTable.Controls.Add(seatsMatch[x]);
}
else
{
flightsSearchedTable.Controls.Add(price[x],1,x+1);
flightsSearchedTable.Controls.Add(airline[x],2,x+1);
flightsSearchedTable.Controls.Add(seatsMatch[x],3,x+1);
}
}
}
And this is what an example flight would look like that is stored in the file:
Southwest 80 Austin Texas Miami Florida 180 12/04/2011
Nevermind I was able to figure it out. I just needed to reset the labels each time when going through the loop.
It does not seem like you have your table layout panel setup to allow multiple flights to be added.
I's assuming you are using visual studio. Create a table layout panel using the ui editor and study the code it creates in the design file. Then add another row of data and study the design file again and take note of what was added.
Make sure that your code des everything VS does to make a new row/col.
Then practice populating the rows/columns in VS and make sure your code does the corectly also

Categories

Resources