I've made a previous post that tried to use a textbox. From this I found out you can simply add an sql query results (the excute reader) to the ComboBox and then display and use the other column value.
Problem I have is I'm using a task for my form that runs a different HUGE sql query so it does not lock up my controls in my form. The problem, in detail, is that I'm using an invoke method wrapped around that control that only gets the 1st column.
public void fillmycombo()
{
SqlConnection conn1 = new SqlConnection(myConn1);
conn1.Open();
if (string.Compare(_userName, admin) == 0)
{
SqlCommand accountFill = new SqlCommand("SELECT name, FROM dbo.Customer", conn1);
SqlDataReader readacc = accountFill.ExecuteReader();
while (readacc.Read())
{
AddItem(readacc.GetString(0).ToString());
//accCollection.DataSource = readacc;
//accCollection.DisplayMember = "name";
//accCollection.ValueMember = "keycode";
}
conn1.Close();
}
}
this method as you can see gets the name.
private void AddItem(string value)
{
if (accCollection.InvokeRequired)
{
accCollection.Invoke(new Action<string>(AddItem), new Object[] { value });
}
else
{
accCollection.Items.Add(value);
}
}
as you can see im using the invoke method to wrap the control for use in my method that is on the task.
private void button1_Click_1(object sender, EventArgs e)
{
checkBox1.Checked = true;
string acct = accCollection.Text;
Task t = new Task(() => GetsalesFigures(acct));
t.Start();
}
this runs the task that calls my giant query method.
private void getsalesfigures(string acct)
{
string acct;// test using 1560
SqlConnection conn = new SqlConnection(myConn);
SqlCommand Pareto = new SqlCommand();
BindingSource bindme = new BindingSource();
SqlDataAdapter adapt1 = new SqlDataAdapter(Pareto);
DataSet dataSet1 = new DataSet();
DataTable table1 = new DataTable();
acct = Acct;
string fromDate = this.dateTimePicker1.Value.ToString("MM/dd/yyyy");
string tooDate = this.dateTimePicker2.Value.ToString("MM/dd/yyyy");
Pareto.Connection = conn;
Pareto.CommandType = CommandType.StoredProcedure;
Pareto.CommandText = "dbo.GetSalesParetotemp";
Pareto.CommandTimeout = 120;
Pareto.Parameters.AddWithValue("#acct", acct);
Pareto.Parameters.AddWithValue("#from", fromDate);
Pareto.Parameters.AddWithValue("#too", tooDate);
SetCheckBoxValue(true);
SetPictureBoxVisibility(true);
adapt1.Fill(dataSet1, "Pareto");
SetCheckBoxValue(false);
SetPictureBoxVisibility(false);
SetDataGrid(true, dataSet1, "Pareto", DataGridViewAutoSizeColumnsMode.AllCells);
dataGridView1.AutoResizeColumns(
DataGridViewAutoSizeColumnsMode.AllCells);
}
catch (Exception execc)
{
MessageBox.Show("Whoops! Seems we couldnt connect to the server!"
+ " information:\n\n" + execc.Message + execc.StackTrace,
"Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
What I want to do is add another field to my query called "keycode", store this in a 2nd column in my ComboBox and then display the name field for the user, but use the keycode field as the value to be used in my giant task query.
I'm having trouble figuring out how I to do this.
In the past, I've used an object that contains an override of ToString() and instead of adding plain strings to my combo boxes (or other lists), I add these objects. Then, when you need to get the value of a selected item, you can cast it and do GetValue(). Here's a sample.
class LookupTableItem {
private string Text;
private object Value;
public LookupTableItem(string Text, object Value) {
this.Text = Text;
this.Value = Value;
}
public override string ToString() {
return Text;
}
public object GetValue() {
return Value;
}
}
Then, change your AddItem to add items this way:
accCollection.Items.Add(new LookupTableItem(text, value));
And to retrieve the value:
((LookupTableItem)accCollection.Items[0]).GetValue();
Related
I am trying to overwrite a content in an label several times by always clicking the same button. Unfortunately, I only know how to override it once.
The problem I am facing is that the data in the label are from an SQL database and it only displays the data with ID = 1 in the label.
This is my code:
MySqlConnection conn = new MySqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString); // Connectionstring to the database
public MainWindow()
{
InitializeComponent();
}
private void btContinue_Click(object sender, RoutedEventArgs e)
{
try
{
conn.Open();
MySqlCommand cmd = new MySqlCommand("SELECT l_question from l_liescale", conn);
MySqlDataAdapter adp = new MySqlDataAdapter(cmd);
DataSet ds = new DataSet();
lbquestion.Content = cmd.ExecuteScalar(); //here I get the data into the label
}
catch (MySqlException ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
conn.Close();
}
}
}
Is there a way to display every data record from the database in one label and always overwriting it with the next record by clicking the button?
You should use ExecuteReader() instead of ExecuteScalar() to retrieve collection of data.
StringBuilder sb = new StringBuilder();
using(var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var question = reader[0].ToString();
sb.AppendFormat("Q: {0}\n", question); // use any other format if needed
}
}
lbquestion.Content = sb.ToString();
But the better way is to use ItemsControl or ListBox or other list-controls.
If you want to iterate by clicking the button you can retrieve all records to the memory and then iterate it in the event handler:
private readonly List<string> _questions;
private int currentIndex = -1;
public MainWindow()
{
InitializeComponent();
_questions = GetQuestionsByDataReader();
}
private void btContinue_Click(object sender, RoutedEventArgs e)
{
if(currentIndex < _questions.Count)
{
lbquestion.Content = _questions[++currentIndex];
}
}
I am learning C# and SQL Server. I was following a simple tutorial, which led me to the creation of a class DBconnection that connects and updates the DB. Then I have a simple C# form that navigates back and forth on table rows using a button and a DataSet to clone the data, and then displays the info on some labels.
No problem 'till here, but then I thought, what if I wanted to display a single value(column) of a specific row, say "show me the last name of the person with a certain first name".
I'm familiar with the SQL query commands, so what I want is something like this:
SELECT last_name FROM Employees WHERE first_name = 'Jason'
Follows my code...
DBconnection.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace cemiGEST
{
/// <summary>
/// A class that makes the connection to the SQL Database
/// </summary>
class DBconnection
{
// variables
private string sql_string;
private string strCon;
System.Data.SqlClient.SqlDataAdapter da_1;
// set methods
public string Sql
{
set { sql_string = value; }
}
public string connection_string
{
set { strCon = value; }
}
// DataSet
public System.Data.DataSet GetConnection
{
get { return MyDataSet(); }
}
// MyDataSet method
private System.Data.DataSet MyDataSet()
{
System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(strCon);
con.Open();
da_1 = new System.Data.SqlClient.SqlDataAdapter(sql_string, con);
System.Data.DataSet dat_set = new System.Data.DataSet();
da_1.Fill(dat_set, "Table_Data_1");
con.Close();
return dat_set;
}
// Update DB method
public void UpdateDB(System.Data.DataSet ds)
{
System.Data.SqlClient.SqlCommandBuilder cb = new System.Data.SqlClient.SqlCommandBuilder(da_1);
cb.DataAdapter.Update(ds.Tables[0]);
}
}
}
I am accessing the values (when moving back and forth) by just incrementing by one a variable that updates the row number. Some exemplifying code follows.
public partial class Example : Form
{
// variables
DBconnection objConnect;
string conStringAUTH;
DataSet ds;
DataRow dr;
int maxRows;
int inc = 0;
private void Login_Load(object sender, EventArgs e)
{
CloseBeforeLogin = true;
try
{
objConnect = new DBconnection();
conStringAUTH = Properties.Settings.Default.authConnectionString;
objConnect.connection_string = conStringAUTH;
objConnect.Sql = Properties.Settings.Default.authSQL;
ds = objConnect.GetConnection;
maxRows = ds.Tables[0].Rows.Count;
if (maxRows == 0)
{
MessageBox.Show("No user found. Loading first run wizard.");
NewUser newUser = new NewUser();
newUser.ShowDialog();
}
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
}
I'm sure this is simple, but I'm not getting there.
EDIT:
I would prefer using my class DBconnection and without external libraries. I'm not at the PC with the project, so can't test anything right now, but after a good night of sleep over the matter, and after (re)looking at my code, I may have found the answer. Please tell me if you think this would do the trick:
In my second class (where I connect to and access the DB), I have already using a SQL query, more specifically here:
objConnect.Sql = Properties.Settings.Default.authSQL;
This query (authSQL), was created by me and embedded on the Settings, and here I am importing it. So, if I do the following instead, do you think it would work:
objConnect.Sql = "SELECT last_name FROM Employees WHERE first_name = 'Jason'";
The "Properties.Settings.Default.authSQL" code is nothing more than a shortcut to a string "SELECT * FROM AUTH" - AUTH is my table, which I called Employees for the sake of simplicity.
So, it would be something like this:
public partial class Example : Form
{
// variables
DBconnection objConnect;
string conStringAUTH;
DataSet ds;
DataRow dr;
int maxRows;
int inc = 0;
private void Login_Load(object sender, EventArgs e)
{
CloseBeforeLogin = true;
try
{
objConnect = new DBconnection();
conStringAUTH = Properties.Settings.Default.authConnectionString;
objConnect.connection_string = conStringAUTH;
objConnect.Sql = "SELECT last_name FROM Employees WHERE first_name = 'Jason'";
ds = objConnect.GetConnection;
// Data manipulation here
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
There's no need for a dataset here. If you know the sql you want: use it - perhaps with some parameterization. For example, using "dapper", we can do:
string firstName = "Jason";
var lastNames = con.Query<string>(
"SELECT last_name FROM Employees WHERE first_name = #firstName",
new { firstName }).ToList();
Check this ....hope this also works...
//String Declaration
string Sqlstr = "select CountryCode,Description,Nationality from ca_countryMaster where isDeleted=0 and CountryCode = 'CAN' ";
string DBCon = "Data Source=RAJA;Initial Catalog=CareHMS;Integrated Security=True;";
SqlConnection SqlCon = new SqlConnection(DBCon);
SqlDataAdapter Sqlda;
DataSet ds = new DataSet();
try
{
SqlCon.Open();
Sqlda = new SqlDataAdapter(Sqlstr, SqlCon);
Sqlda.Fill(ds);
gdView.DataSource = ds.Tables[0];
gdView.DataBind();
}
catch (Exception ex)
{
lbl.text = ex.Message;
}
finally
{
ds.Dispose();
SqlCon.Close();
}
I want to allow user to add rows but the blank row must be in he first position to let the user enter data without scroll down each time to insert a new row ?!
This is how I add the rows in the datagridview :
using System;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.Windows.Forms;
namespace Parc_Automobile
{
public class SqlHelper
{
private const string ConnectionString =
"Data Source=KIM;Initial Catalog=TestingBlank;Integrated Security=True";
private readonly DataGridView _dgv;
private BindingSource _bindingSource;
private DataTable _dataTable;
private string _selectQueryString;
private SqlConnection _sqlConnection;
private SqlDataAdapter _sqlDataAdapter;
protected SqlHelper(DataGridView dgv)
{
_dgv = dgv;
}
//display a table in datagridview
public void ShowTable(String tableName)
{
_sqlConnection = new SqlConnection(ConnectionString);
_sqlConnection.Open();
_selectQueryString = "SELECT * FROM " + tableName;
_sqlDataAdapter = new SqlDataAdapter(_selectQueryString, _sqlConnection);
var sqlCommandBuilder = new SqlCommandBuilder(_sqlDataAdapter);
_dataTable = new DataTable();
_sqlDataAdapter.Fill(_dataTable);
_bindingSource = new BindingSource {DataSource = _dataTable};
var tempRow = this._dataTable.NewRow();
this._dataTable.Rows.InsertAt(tempRow, 0);
_dgv.DataSource = _bindingSource;
_sqlConnection.Close();
}
//Search In datagridview using input of users
public void SearchTable(String SearchText, String columnNameToSearch, int type)
{
try
{
var filterBuilder = "";
switch (type)
{
case TEXT_COLUMN:
filterBuilder = columnNameToSearch + " LIKE '" + SearchText + "%'";
break;
case NUMERIC_COLUMN:
filterBuilder = columnNameToSearch + " = '" + SearchText + "'";
break;
}
var bs = new BindingSource
{
DataSource = _dgv.DataSource,
Filter = filterBuilder
};
_dgv.DataSource = bs;
}
catch (Exception e)
{
// ignored
}
}
public void DeleteRow()
{
if (_dgv.CurrentRow != null) _dgv.Rows.RemoveAt(_dgv.CurrentRow.Index);
_sqlDataAdapter.Update(_dataTable);
}
public void SaveChanges(Label label)
{
try
{
_sqlDataAdapter.Update(_dataTable);
label.Text = "Changement a été effectué avec succès.";
}
catch (Exception e)
{
MessageBox.Show("" + e);
}
}
}
}
When you add a new row use the Insert method instead of Add. Insert allows to specify the index for the new row. Set the index to 0:
this.dataGridView1.Rows.Insert(0,new DataGridViewRow());
EDIT I
Adjusting the answer to your comment: if you are using a binding to a data source you have to create a new row using the data source. Then you insert it at specified position. Let's say that you have myDataSet data source with a Log table in it. This code will create a new row and insert it as the first row:
var tempRow = this.myDataSet.Log.NewRow();
this.myDataSet.Log.Rows.InsertAt(tempRow, 0);
Your DataGridView will be updated appropriately.
EDIT II
You will get exception if you try, for instance, to assign data type different than a column type in your table. Say the ID column is int but you try to add string. To handle data errors you have to handle the DataError event. Below an example using your code.
protected SqlHelper(DataGridView dgv)
{
_dgv = dgv;
_dgv.DataError += _dgv_DataError;
}
void _dgv_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
if (e.Exception != null)
{
MessageBox.Show(string.Format("Incorrect data: {0}", e.Exception.Message) );
e.Cancel = false;
// handle the exception
}
}
I have a combobox that is bound with a datasource. In this combobox I have to add a blank field at index 0.
I have written following code for getting records.
public List<TBASubType> GetSubType(int typ)
{
using (var tr = session.BeginTransaction())
{
try
{
List<TBASubType> lstSubTypes = (from sbt in session.Query<TBASubType>()
where sbt.FType == typ
select sbt).ToList();
tr.Commit();
return lstSubTypes;
}
catch (Exception ex)
{
CusException cex = new CusException(ex);
cex.Write();
return null;
}
}
}
After this it bind with combobox with data binding source as below code.
M3.CM.BAL.CM CMobj = new M3.CM.BAL.CM(wSession.CreateSession());
lstSubTypes = CMobj.GetSubType(type);
this.tBASubTypeBindingSource.DataSource = lstSubTypes;
If you just want to select nothing initially, you can use
comboBox1.SelectedIndex=-1;
Thus you can't modify Items when you are are bound to DataSource, then only option to add blank row is modifying your data source. Create some empty object and add it to data source. E.g. if you have list of some Person entities bound to combobox:
var people = Builder<Person>.CreateListOfSize(10).Build().ToList();
people.Insert(0, new Person { Name = "" });
comboBox1.DisplayMember = "Name";
comboBox1.DataSource = people;
You can define static property Empty in your class:
public static readonly Person Empty = new Person { Name = "" };
And use it to insert default blank item:
people.Insert(0, Person.Empty);
This also will allow to check if selected item is default one:
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
Person person = (Person)comboBox.SelectedItem;
if (person == Person.Empty)
MessageBox.Show("Default item selected!");
}
cboCustomers.Items.Add(""); // Just add a blank item first
// Then load the records from the database
try
{
OleDbConnection con = new OleDbConnection(strDBConnection);
OleDbCommand cmd = new OleDbCommand();
con.Open();
cmd.Connection = con;
cmd.CommandText = "SELECT * FROM Customers";
OleDbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
cboCustomers.Items.Add(dr["Name"]);
}
con.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
After creating my combo boxes, I added these lines to the end of the Load() method:
private void xyz_Load(object sender, EventArgs e)
{
this.xyzTableAdapter.Fill(this.DataSet.xyz);
this.comboBoxXYZ.SelectedIndex = -1;
}
replace xyz with the names you've given to your controls
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