First time messing around with c# and I am trying to change the value of a button when the user clicks it.
The database has four names in it, when the code executes it only shows the name that is in the last row. I would like it to start with the first name, and then each time the button is pressed it should show another name until it has gone through all the names in the DB.
dataReader = command.ExecuteReader();
while (dataReader.Read())
{
bText = dataReader.GetValue(1).ToString();
button1.Text = bText;
}
The while loop does not work the way you think it does. What it does is looping over every result and set the button text. It does not pause anywhere (because there is nothing that tells the loop it should). So it simply iterates over every element as fast as it can. This explains why you only see the last result.
What you can do is to store a counter somewhere that you increment every time the button is pressed and only use the n-th element. Either by skipping the first few entries or depending on the database you use, you could only fetch a specific result entry (in MySQL this would be LIMIT and OFFSET in the select query)
For your specific problem (only 4 entries) I would fetch all entries at the start of the application and store them in an array. Then use the entry at the current index (=your counter) to set the text of the button.
You can try this. I've table named Colors having two columns: ID and Name.
public partial class FrmColor : Form
{
SqlConnection con = new SqlConnection(#"<YOUR CONNECTION STRING HERE>");
int pointer = 1;
int rows = 0;
public FrmColor()
{
InitializeComponent();
}
private void btnColor_Click(object sender, EventArgs e)
{
SqlCommand cmd = new SqlCommand("Select Name from Colors Where ID = #ID", con);
cmd.Parameters.AddWithValue("#ID", pointer);
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
rdr.Read();
string colorname = rdr.GetValue(0).ToString();
con.Close();
btnColor.Text = colorname;
if (pointer == rows)
{
pointer = 1;
}
else
{
pointer++;
}
}
private void FrmColor_Load(object sender, EventArgs e)
{
SqlCommand cmd = new SqlCommand("Select count(Name) From Colors", con);
con.Open();
rows = (Int32)cmd.ExecuteScalar();
con.Close();
}
}
Don't forget to add using System.Data.SqlClient;
Hope this helps.
Related
how can achieve dynamic auto complete textbox in c# winform?
for example ,in my application have a textbox named txtbox_mobileno.
i wanna bind mobile number(from database table named customer) with txtbox_mobileno.
the table customer have more than 100,000 records .client want suggestion list while typing mobile number in application .
so i tried to implement following code on textchanged event
if (txtbox_mobileno.TextLength >3)
{
cmd.CommandText = "SELECT TOP 20 MobileNo FROM Customer WHERE MobileNo LIKE'" + txtbox_mobileno.Text+"%'";
SqlDataReader dr;
dr = RunSqlReturnDR(cmd);//return value
if (dr.HasRows)
{
while (dr.Read())
{
C.Add(dr[0].ToString()); //AutoCompleteStringCollection C = new AutoCompleteStringCollection();
}
}
dr.Close();
txtbox_mobileno.AutoCompleteMode = AutoCompleteMode.Suggest;
txtbox_mobileno.AutoCompleteSource = AutoCompleteSource.CustomSource;
txtbox_mobileno.AutoCompleteCustomSource = C;
}
i want to show the suggestion list only if text box have more than 3 letters
when tried to bind on load event, it took around 5 minutes to bind data with textbox suggestion list ,
Sql server query execution time was only 3 seconds.
is there any fastest way to overcome this issue?
I am not sure if you are able to grab all mobile numbers at the beginning of your app or at least when your data entry form loads up, but if so, it may be easier to load all of the numbers into buckets with the first three characters being the key for the list of numbers. Even if you had 1,000,000 numbers, you are only talking around 30 MB of data (assuming I did my math correctly), so you shouldn't have any issues in that regard. You could do something like this to build your buckets. As an aside, I also have no idea how many numbers you get that have the same first three digits, so I may be building very large autocomplete lists in this code which would be another problem. Your code only pulled back the top 20, you could modify this code to only keep the first 20 or something like that.
var buckets = new Dictionary<string, List<string>>();
cmd.CommandText = "SELECT MobileNo FROM Customer";
SqlDataReader dr = RunSqlReturnDR(cmd);
if (dr.HasRows)
{
while (dr.Read())
{
var number = dr[0].ToString();
var key = number.Substring(0, 3);
List<string> numbers = null;
if(!buckets.TryGetValue(key, out numbers))
{
numbers = new List<string>();
}
numbers.Add(number);
}
}
dr.Close();
Then in your event handler you just need to do something like this:
if (txtbox_mobileno.Text.Length == 3)
{
List<string> numbers;
if (_buckets.TryGetValue(txtbox_mobileno.Text, out numbers)
{
var ac = new AutoCompleteStringCollection();
ac.AddRange(numbers.ToArray());
txtbox_mobileno.AutoCompleteMode = AutoCompleteMode.Suggest;
txtbox_mobileno.AutoCompleteSource = AutoCompleteSource.CustomSource;
txtbox_mobileno.AutoCompleteCustomSource = ac;
}
}
Other ways you could potentially enhance this would be to add an order by in the query where you get the numbers, then you should be able to walk the values and just create a new list when you hit a change in the first three digits. That would make it easier to build a dictionary of arrays rather than a dictionary of lists, which would then help in your autocomplete box. I also haven't written a lot of DB code in a while, so I just kept the code you posted for getting the data out of the database. It is possible that there may be better ways to read the data from the database.
Try use a timer to fire query, and a Thread to execute, see:
private void textBox1_TextChanged(object sender, EventArgs e)
{
timer1.Enabled = false;
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled = false;
string filter = txtbox_mobileno.Text;
Thread t = new Thread(() => {
cmd.CommandText = "SELECT TOP 20 MobileNo FROM Customer WHERE MobileNo LIKE '" + filter + "%'";
SqlDataReader dr;
dr = RunSqlReturnDR(cmd);//return value
if (dr.HasRows)
{
while (dr.Read())
{
C.Add(dr[0].ToString()); //AutoCompleteStringCollection C = new AutoCompleteStringCollection();
}
}
dr.Close();
txtbox_mobileno.Invoke((MethodInvoker)delegate {
txtbox_mobileno.AutoCompleteMode = AutoCompleteMode.Suggest;
txtbox_mobileno.AutoCompleteSource = AutoCompleteSource.CustomSource;
txtbox_mobileno.AutoCompleteCustomSource = C;
});
});
t.Start();
}
I have in my database a table called students that have the number and name, address....
I have a form where I load all information for one student at a a time , and I have a next button and a back button.
How can I iterate to the next row (or previous row) in mysql (to be able to see the info of the next student) ?
I tried to use the primary key (auto increment) to iterate and when I want to see the next record I add 1 to the id or subtract 1 to see the previous record.
But if one record is deleted it will show an empty record.
Can you point me in the rigth direction?
I´m using WinForms
Sorry about my english..
string config = "server=localhost; userid = root; database = databaseName";
MySqlConnection con = new MySqlConnection(config);
MySqlDataReader reader = null;
string query = "SELECT * FROM students WHERE id = " + id; //id is the primary Key (auto increment)
MySqlCommand command = new MySqlCommand(query, con);
con.Open();
reader = command.ExecuteReader();
while (reader.Read())
{
string studentName = (string)reader["studentName"];
string studentNum = (string)reader["studentNum"];
tbstudentName.Text = Convert.ToString(studentName);
tbstudentNum.Text = Convert.ToString(studentNum);
.....
}
con.Close();
You should not be calling the database each time you want to view the next record. Try reading all the data into a List.
I am not sure what you are using.. WinForms? WPF?
If WinForms you will need to do something like this.
public class Student
{//First create a class to hold your data in
public string Name { get; set; }
public string Num { get; set; }
}
public class MyForm : Form
{
int Index = 0;
List<Student> FormData { get; set; }
void GetData()
{
//This will hold all your data in memory so you do not have to make a database call each and every "iteration"
List<Student> dbData = new List<Student>();
string config = "server=localhost; userid = root; database = databaseName";
MySqlConnection con = new MySqlConnection(config);
MySqlDataReader reader = null;
string query = "SELECT * FROM students";
MySqlCommand command = new MySqlCommand(query, con);
con.Open();
reader = command.ExecuteReader();
while (reader.Read())
{
Student newStudent = new Student();
newStudent.Name = (string)reader["studentName"];
newStudent.Num = (string)reader["studentNum"];
//Add data to the list you created
dbData.Add(newStudent);
.....
}
con.Close();
//set the Form's list equal to the one you just populated
this.FormData = dbData;
}
private void BindData()
{
//If winforms
tbstudentName.Text = FormData[Index].Name;
tbstudentNum.Text = FormData[Index].Num;
//If wpf you will have to use view models and bind your data in your XAML but I am assuming you are using
//winforms here.
}
private void NextRecord()
{ //If you reached the end of the records then this will prevent IndexOutOfRange Exception
if (Index < FormData.Count - 1)
{
Index++;
BindData();
}
}
private void PreviousRecord()
{
if (Index != 0)
{
Index--;
BindData();
}
}
}
Now the above scenario will get it working quickly; however, there are better ways in doing this that would help you when you need to alter that data. I would recommend WinForms Binding. You can check it out here http://msdn.microsoft.com/en-us/library/c8aebh9k(v=vs.110).aspx
To get the next you can write:
select * from students where id > #id
order by id asc
limit 1
And to get previous
select * from students where id < #id
order by id desc
limit 1
DataReader Designed to quick one-time read.
If you want to hold the data, you need to fill memory arrays.
the DataTable implements it very well.
You will need to think a little different.
Getting id+1 you are being very careless.. Even identity, the Id can be another value and you will get an Exception.. I suppose that you don't want it.
You will need to Adjust your logic to return lines with top or, in mysql, limit statement..
This will be easy using lambda to use .Take() and Skip() methods...
You also can use the limit parameter to pass throug this sample.. you can understand..
MySQL skip first 10 results
Hope it helps.
How do I read data in ms access database and display it in a listbox. I have the codes here but i got errors.
private void button3_Click(object sender, EventArgs e)
{
using (OleDbConnection conn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=\\Sisc-stronghold\mis!\wilbert.beltran\DataBase\DataStructure.accdb"))
using(OleDbCommand cmd = new OleDbCommand(" SELECT * from TableAcct", conn))
{
conn.Open();
OleDbDataReader Reader = cmd.ExecuteReader();
//if (Reader.HasRows)
if (Reader.HasRows)
{
Reader.Read();
listBox1.Text = Reader.GetString("FirstName");
}
}
the errors are here:
1. Error 1 The best overloaded method match for'System.Data.Common.DbDataReader.GetString(int)' has some invalid arguments.
2. Error 2 Argument '1': cannot convert from 'string' to 'int'
try this one,
List<String> firstName = new List<String>();
List<String> lastName = new List<String>();
private void loadButton_Click(object sender, EventArgs e)
{
cn.Open();
OleDbDataReader reader = null;
cmd = new OleDbCommand("select* from Records", cn);
reader = cmd.ExecuteReader();
while (reader.Read())
{
firstName.Add(reader["FirstName"].ToString());
lastName.Add(reader["LastName"].ToString());
}
cn.Close();
}
then in your search button, insert this,
private void searchButton_Click(object sender, EventArgs e)
{
clearSearchResult();
try
{
int totalItems = FirstName.Count;
int count = 0;
while (count < totalItems)
{
if (textBox6.Text == FirstName[count].ToString())
{
listBox1.Items.Add(FirstName[count].ToString());
count = 100;
}
else
{
count++;
}
It's good to use when you want to show the information of the "FirstName" in the listBox1_SelectedIndexChanged if you want. here's an example,
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
int totalItems = lastName.Count;
int count = 0;
while (count < totalItems)
{
if ((listBox1.SelectedItem.ToString()) == firstName[count].ToString()))
{
textBox1.Text = firstName[count].ToString();
textBox2.Text = lastName[count].ToString();
count = 100;
}
else
{
count++;
}
}
hope this helps,
change
listBox1.Text = Reader.GetString("FirstName");
to
listBox1.Text = Reader.GetString(0); // zero base ordinal of column
GetString() takes an int as the parameter and not a string. Meaning that you must use the index of the column.
In your specific circumstance as "FirstName" is the second column the index would be 1:
listBox1.Text = Reader.GetString(1);
http://msdn.microsoft.com/en-us/library/system.data.oledb.oledbdatareader.getstring.aspx
Thy using a While loop
while(reader.Read())
{
listbox1.Items.Add(reader["FirstName"]);
}
This moves through all the rows you selected. reader.Read() returns false if there are no more rows.
Also: if you Want to retrive valmue from a column I suggest you do it with the index ón the reader instance. Like my example.
var value = reader["ColumnName"];
This increases readability comparing to
var value = reader.GetString(0);
UPDATE
If you want to only display the fist value - I suggest you use cmd.ExecuteScalar() and the adapt you sql to only return the value you need:
using(OleDbCommand cmd = new OleDbCommand("SELECT firstname from TableAcct", conn))
{
conn.Open();
var firstName = cmd.ExecuteScalar();
}
Be aware the this will give you the first "FirstName" in the table. And since there is no "order by firstname" or "where someKey = 1" - this might not rturn that you expected.
If you want to create MS Access data base and to access it, and to display data in some component, like here i will show you.how to connect with MS Access Data Base and display data from data base in Label.
First of all create any Access data base like here "PirFahimDataBase".
Now in your Visual Studio go to the menu and do this
Click Data
Add New Data Base
Click Next
Click New Connection
Now change the Data Source by clicking Change and select Microsoft Access data base files
Click Browse for selecting your created data base
Now in Button ClickEvent paste these code which will get data from data base and will show it in the label
using System.Windows.Forms; //these two lines should be written before namespace at top of the program
using System.Data.OleDb;
private void button1_Click(object sender, EventArgs e)
{
System.Data.OleDb.OleDbConnection conn = new System.Data.OleDb.OleDbConnection();
conn.ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;" +
#"Data source= C:\Users\pir fahim shah\Documents\PirFahimDataBase.accdb";
try
{
conn.Open();
MessageBox.Show("connected successfuly");
OleDbDataReader reader = null; // This is OleDb Reader
OleDbCommand cmd = new OleDbCommand("select TicketNo from Table1 where Sellprice='6000' ", conn);
reader = cmd.ExecuteReader();
while (reader.Read())
{
label1.Text= reader["TicketNo"].ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("Failed to connect to data source");
}
finally
{
conn.Close();
}
}//end of button click event
Your error is in this line:
listBox1.Text = Reader.GetString("FirstName");
You must pass a number in the GetString() function.
DataColumn[] PrimaryKeyColumn = new DataColumn[1]; //Define Primary coloumn
DataSet dataSet = new DataSet();
DataTable dataTable = new DataTable();
ReadAndUpdateExcel.ReadExcel(strPath, sheetName, out dataSet);
dataSet.Tables.Add(dataTable);
PrimaryKeyColumn[0] = dataSet.Tables[0].Columns[0];
dataSet.Tables[0].PrimaryKey = PrimaryKeyColumn;
string num = dataSet.Tables[0].Rows[dataSet.Tables[0].Rows.IndexOf(dataSet.Tables[0].Rows.Find(strTCName))]["ACNO"].ToString();
//string country
I have what is a very elementary problem I realize, I am trying to return a string value from a selected value of a DropDownList upon selected index change but for some or other reason it is not happening.
protected void drpMinisters_SelectedIndexChanged(object sender, EventArgs e)
{
name = drpMinisters.SelectedValue;
LabMessage.Text = name;
}
When I try to add name to a database I get a NullReferenceException.
protected void butSubmitMinister_Click(object sender, EventArgs e)
{
int index = drpMinisters.SelectedIndex;
if (index == 0)
{
LabMessage.Text = "Please select a minister";
return;
}
try
{
OleDbCommand cmd = conn.CreateCommand();
cmd.CommandText = #"INSERT INTO MinisterTable(MinisterName)VALUES(" + name + "')";
cmd.ExecuteNonQuery();
LabMessage.Text = "The record was successfully added";
conn.Close();
}
catch (Exception ex)
{
LabMessage.Text = ex.ToString();
}
}
Advice perhaps.
I assume that you get the NullRefernceException on your connection object conn on this line:
OleDbCommand cmd = conn.CreateCommand();
Remember that all objects (also your name variable) are disposed at the end of the current page-lifecycle. You can use the control's ViewState to maintain values across postbacks, f.e. the SelectedValue property of your DropDownList.
You should also create the connection where you use it and always dispose it as soon as you're finished, best by using the using-statement. Otherwise other threads(requests) would need to create a new physical connection whenever this is still open:
string sql = "INSERT INTO MinisterTable(MinisterName) VALUES(#MinisterName);";
using(var con = new OleDbConnection(connectionString))
using(var cmd = new OleDbCommand(sql, con))
{
cmd.Parameters.AddWithValue("#MinisterName", drpMinisters.SelectedValue);
con.Open();
cmd.ExecuteNonQuery();
}
well i dont think your problem is with the database part, it actually lies in how you are getting the selected value from your dropdown list. if you want to get the string value that actually appears in the dropdown list, then you should use the following .
string name= (string)drpMinisters.SelectedItem;
in case you want the text in the text area of combobox then use SelectedText property
This is my code:
private void CostList_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'lSEStockDataSet.CostPrice' table. You can move, or remove it, as needed.
this.costPriceTableAdapter.Fill(this.lSEStockDataSet.CostPrice);
con = new System.Data.SqlClient.SqlConnection();
con.ConnectionString = "Data Source=tcp:SHEN-PC,49172\\SQLEXPRESS;Initial Catalog=LSEStock;Integrated Security=True";
con.Open();
DataGridView datagridview1 = new DataGridView();
String retrieveData = "SELECT CostID, SupplierName, CostPrice FROM CostPrice WHERE PartsID ='" + textBox1.Text + "'";
SqlCommand cmd = new SqlCommand(retrieveData, con);
int count = cmd.ExecuteNonQuery();
SqlDataReader dr = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
dataGridView1.DataSource = dt;
con.Close();
}
private void button1_Click(object sender, EventArgs e)
{
if (dataGridView1.Rows.Count > 0)
{
int nRowIndex = dataGridView1.Rows.Count-1;
if (dataGridView1.Rows[nRowIndex].Cells[2].Value != null)
{
textBox2.Text = Convert.ToString(dataGridView1.Rows[nRowIndex].Cells[2].Value);
}
else
{
MessageBox.Show("NULL");
}
}
}
It shows NULL when i clikc the button, what is the problem here? I have 3 columns there, i want to get the data of the 3rd column of the last row, but it shows NULL but there is data in the specified cell. Anyone knows how to solve this problem?
Instead of subtracting one from the row count, try subtracting two. Subtracting one is giving you the zero-based index of the "add" row, which indeed has a null value in the last column.
int nRowIndex = dataGridView1.Rows.Count-2;
By subtracting 2 from the count, you will get the zero-based index of the last row with actual data in it. I think this is what you are looking for.
As an aside, you will likely want to parameterize your SQL query, something like this:
String retrieveData = "SELECT CostID, SupplierName, CostPrice FROM CostPrice WHERE PartsID = #inPartsID";
SqlCommand cmd = new SqlCommand(retrieveData, con);
cmd.Parameters.Add(new SqlParameter("#inPartsID", textBox1.Text));
This will make your query more reliable (what happens if there is a single quote character in textBox1) and your data more secure (evil-doers can use SQL injection to cause harm to your database or get data out of it that they shouldn't).