TextBox AutoComplete from MDB - c#

I have a .Net 4 Windows Forms app that uses a Microsoft Access Database with one table which has three columns CityCode, Name and Country.
What I want to do is have an autocomplete which shows the “Name” and “Country” but when selected the “CityCode” Value is shown in the textbox. In addition if the user types A City Code eg LAX as they type L it would list all the cities whose code or Name starts with L.
Can this be done?
Currently I have the following for access the database (but it seems to be a bit slow!)
textBoxCity.AutoCompleteCustomSource = CityList();
public static AutoCompleteStringCollection CityList()
{
string connectionStringLD = string.Empty;
connectionStringLD = #"Driver={Microsoft Access Driver (*.mdb)};DBQ=c:\CityList.mdb";
string SQL = "SELECT CityCode from CityTable";
OdbcConnection conn = new OdbcConnection(connectionStringLD);
OdbcCommand cmd = new OdbcCommand(SQL);
cmd.Connection = conn;
conn.Open();
OdbcDataReader reader = cmd.ExecuteReader();
AutoCompleteStringCollection theCityList = new AutoCompleteStringCollection();
while (reader.Read())
{
theCityList.Add(reader.GetValue(0).ToString());
}
return theCityList;
}

You can use Like '%' Query in your Sql Statement which will return the city name based on your input.
You can Refer this example Sql Parameter with C# Using Like wildCards

I'm not sure what you're getting at with
What I want to do is have an autocomplete which shows the “Name” and “Country” but when selected the “CityCode” Value is shown in the textbox.
but I can answer the autocomplete part of your question.
To do this you need to get your data into a DataTable; you can read it from the database into the table however you want, but the Right Way to do it is to use OleDbConnection, OleDbDataAdapter, and OleDbCommandBuilder - msdn has examples.
Now that it's in a DataTable, bind it to a ComboBox:
var query =
from row in mytable.AsEnumerable()
select new { citycode = row.Field<string>("CityCode") } // put whatever you want in the anonymous type
mycombobox.DisplayMember = "citycode"
mycombobox.ValueMember = "citycode" // this one can be a different member name
mycombobox.DataSource = query.toList(); // the datasource should be set last
And now you can set the combo box behavior to be an autocomplete:
combobox1.AutoCompleteMode can be set to Append (to simply autocomplete), Suggest (to bring up a dropdown box), or SuggestAppend (both)
Set combobox1.AutoCompleteSource to ListItems to have it get the autocomplete entries from the data binding.
If you prefer to allow users to type whatever they want and only suggest your datatable values as options, then you should only set the AutoCompleteCustomSource and not worry about actual data binding with DataSource.
This is kind of all a lot of trouble; since cities aren't exactly going to be opening international airports several times a second you might prefer just dumping all the airport codes into a List, which you can also data bind to.

Related

Problem with format in C# with DataGridView and TextBox

I have a problem with format in C#.
I have a DataGridView and a TextBox. In this datagridview, there is a column: the single price (format int).
I want sum every elements of single price's column and insert the result into this textbox, but Visual Studio gives me a problem with format of string input ("Format of input's string is not correct").
this is the code than i used:
int TOT = 0;
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
TOT = TOT + Convert.ToInt32(dataGridView3.Rows[i].Cells[6].ToString());
}
textBoxTot.Text = Convert.ToString(TOT);
Can you help me with this bad error?
UPDATE:
I think that the problem now is another. I can't find the methods of MySql.Data.MySqlClient library that it can give me the result of query.
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
conn.closeConnection();
How is the command that give me the result of sumQuery. If i find this command, i can take the result of query and paste in textbox
If your datagridview is showing a datatable (I.e. your data is stored in a datatable) you can add a DataColumn to the datatable whose .Expression property is set to the string "SUM([Price])", where Price is the name of your numeric datatyped column holding the price info.
Now every row in the table will have the sum of the prices (the same value over and over again), so if you want to databind your textBox to this new column then it will always show the sum no matter which row is the current row (because all rows have the same value). It will also auto update without you having to do anything!
And if you're not using databinding to a datatable, I recommend that you do do it, because it represents good MVC practice of keeping your data in one thing (DataTable) and showing it in another (DataGridView) and keeping these concerns separate
It would look something like this, as a quick example:
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Price", typeof(int));
dt.Columns.Add("CalculatedTotal", typeof(int)).Expression = "SUM([Price])";
dt.Rows.Add("Apples", 100);
dt.Rows.Add("Oranges", 200);
BindingSource bs = new BindingSource();
bs.DataSource = dt;
WhateverDataGridView.DataSource = bs;
totalTextBox.DataBindings.Add(new Binding("Text", bs, "CalculatedTotal", true));
Here we have a data model (the datatable) where we keep our data. It has a couple of things we can set directly, and an third column that calculates based on the existing prices in all the table. If you look at this in the datagridview (assuming you have autogeneratecolumns turned on) you'll see that both rows have 300 for the CalculatedTotal, but they have individual amounts for price. There is a device called a BindingSource that sits between the datatable and the UI controls; you don't have to have one but it makes certain things easier regards updating controls when the data changes, and it maintains a concept of "current" - essentially whatever the current row is you're looking at in the datagridview; it all helps to avoid having to ask the DGV for anything - we just let the user type into the DGV, and it shows the data out of the datatable. All our dealings can be with the datatable directly - if you wrote a button to loop through the table and double all the prices, the controls in the UI would just reflect the change automatically. The textbox is connected to the CalculatedValue column via databinding; whatever the current row is, the textbox will show the CalculatedValue. Because the CalculatedValue column has the same value on every row, and they always all update if any price changes, the total textbox will always show the total. Add another textbox bound to Name to see what I mean; as you click around the grid and select different rows to be the "Current" row, the Name will change but the total does not. In truth it is actually changing in the same way that Name is, it's just that because the actual numeric value is the same on every row the contents of the textbox look like they don't change
UPDATE: I think that the problem now is another. I can't find the methods of MySql.Data.MySqlClient library that it can give me the result of query.
public string sommaFattura(String costo)
{
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
conn.closeConnection();
}
How is the command that give me the result of sumQuery. If i find this command, i can take the result of query and paste in textbox
It is weird that you are first converting to a string and then to an int.
int TOT = 0;
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
if (!dataGridView3.Rows[i].IsNewRow &&
int.TryParse(dataGridView3.Rows[i].Cells[6].Value.ToString(), out int v))
TOT += v;
}
textBoxTot.Text = TOT.ToString();
EDIT: Edited for your updated question. You shouldn't ask question inside a question buy anyway:
string sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
decimal total = 0M;
using (MySqlConnection cn = new MySqlConnection(" your connection string here "))
using (MySqlCommand cmd = new MySqlCommand(sumQuery, cn))
{
cn.Open();
total = Convert.ToDecimal(cmd.ExecuteScalar());
cn.Close();
}
Console.WriteLine(total);

Error while displaying photo on my datagridview

I can't display photo from heidiSQL in my datagridview. There is an error and I don't know how to cope with it because my source code is exactly the same as a person that I'm study with. Only difference is that he is using phpmyadmin.
Student student = new Student();
private void StudentsList_Load(object sender, EventArgs e)
{
// populate the datagridview with students data
MySqlCommand command = new MySqlCommand("SELECT * FROM `students`");
dataGridView1.ReadOnly = true;
DataGridViewImageColumn picCol = new DataGridViewImageColumn();
dataGridView1.RowTemplate.Height = 80;
dataGridView1.DataSource = student.getStudents(command);
picCol = (DataGridViewImageColumn)dataGridView1.Columns[7];
picCol.ImageLayout = DataGridViewImageCellLayout.Stretch;
dataGridView1.AllowUserToAddRows = false;
}
https://i.stack.imgur.com/Kilx0.png
Error I get
For a start, I would use a column Name instead of an Index; it's where it can get mixed easily. I believe it should be:
picCol = (DataGridViewImageColumn)dataGridView1.Columns["ImageDBColumnName"];
This applies also to your DataSource, SELECT * is a bad practice. You should list your data columns and also refer by their names.
Then, what is the file type of your images? You didn't mention that.
But I would focus also on the order of definitions. You set the properties quite randomly, I would suggest fist to define DataGridView properties such as Columns (most importantly ensure that intended image column is of type DataGridViewImageColumn) and only at the last moment, set the DataGridView.DataSource. Specifically here I see a potential problem:
dataGridView1.DataSource = student.getStudents(command);
picCol = (DataGridViewImageColumn)dataGridView1.Columns[7];
I personally prefer to use GUI to set up DataGridView columns, as it offloads a lot of code from the solution and you can be sure, they are set before your code is executed. However, if your datasource happens to be empty, you will loose those definitions. An easy solution is to use DataTable as data mediator.
I already fixed the problem. I needed to add .ToArray() to my picture variable when I was converting it into parameter.
MySqlCommand command = new MySqlCommand();
String editQuery = "sql query";
command.CommandText = editQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#pic", MySqlDbType.Blob).Value = picture.ToArray();

Using a list retrieved from a SQLite query in a 'foreach' statement

I'm currently converting some code that stores data in an XML file to storing it in a SQLite database instead. The database has a single table with 4 columns:
thumbnail | title | threadid | url
All of the entries in the database are strings. With my old code, I extract all the data from an XML file and populate a datagrid with the values. My aim is to do just that but using data pulled from the SQLite database. I can successfully extract all the data from the database table like so:
public List<Database> getFromTable()
{
List<Database> items = new List<Database>();
string sql = "SELECT * FROM blacklist";
SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);
using (SQLiteDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
var item = new Database();
item.imgstring = (string)reader["thumbnail"];
item.titlestring = (string)reader["title"];
item.threadidstring = (string)reader["threadid"];
item.urlstring = (string)reader["url"];
items.Add(item);
}
}
return items;
}
The part I'm now stuck on is how to use the results returned in the list. Currently I'm calling the method like so:
var items = database.getFromTable();
However after failing to find some examples, I can't work out how to put the foreach line together use the items in the returned list. Eg;
foreach (??? in items)
{
// Populate line in datagrid with thumbnail, title, threadid, url
}
I can get the datagrid populated, it's just understanding how to breakdown my 'items' into a usable form. Any pointers appreciated.
Edit I will be adding this information into a data-grid so each cell value from the SQLite table will be added into a matching cell on the data-grid.
Edit 2 It's worth mentioning that while thumbnail from my SQLite database is a string value, it's actually an image that's been converted to a Base64ImageRepresentation so I can store it as a string value. Part of getting each value from the SQLite database is so I can convert this string back to an image before adding in into my DataGridView.
It would be easier to forego the custom objects, and instead just read a DataTable and use it as the source of the DataGridView directly.
If you must use the custom objects, then you will have to loop over them, create rows from the grid's data source, and populate the rows one by one, adding them back once populated.
Something like this:
foreach (var item in getFromTable())
{
var index = grid.Rows.Add();
var row = grid.Rows[index];
row.SetValues(item.imgstring, item.titlestring, item.threadidstring, item.urlstring); //order of the items must match field order in grid
}
Still, I would opt for the option of binding to a solid data source. But this should give you the general idea.

ComboBox Index Changed

Need to know: I am working with Windows Forms in Visual Studio and C#.
I have 5 comobobox's that I populate from SQL with the parts available in the DB. Part of the coding to it, one uses a DataTable and set the DataSource of the comboBox to that DataTable.
In this same DataTable via my SQL query, I have listed the cost of the part in the list. What I want to do is whichever part you pick from the dropdown list, the related price must show in the textbox next to it.
I am trying to use the comboBox1_SelectedIndexChanged for this, but the problem I run into is as soon as the DataSource gets set to the DataTable while the form's initial loading, it gets picked up as a Index change and the comboBox1_SelectedIndexChanged wants to run. But at this point in time, the SelectedIndex Value is null due to it still loading, causing it to give me a exception cast error.
how can I work around this?
DataTable SparePart = new DataTable() is declared outside the function to make it available as "public" so that the comboBox1_SelectedIndexChanged can access it.
Then I have this code to populate the comboBox:
//Read Status info from DB
SqlDataAdapter SparePartReader = new SqlDataAdapter(SQLSparePartDropbox);
SparePartReader.Fill(SparePart);
comboBoxFinJCSpares1.DataSource = SparePart;
comboBoxFinJCSpares1.DisplayMember = "DisplayMember";
comboBoxFinJCSpares1.ValueMember = "PartID";
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
and then I have this for the comboBoxFinJCSpares1_SelectedIndexChanged:
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
enter image description here
The solution is as easy as making one boolean variable and call it formLoaded.
Set it to false, then set it to true after the form loads.
Put your code for populating combobox inside if statement and that should do it
Cheers ~ ChenChi
demo:
//Read Status info from DB
if(formLoaded)
{
SqlDataAdapter SparePartReader = new SqlDataAdapter(SQLSparePartDropbox);
SparePartReader.Fill(SparePart);
comboBoxFinJCSpares1.DataSource = SparePart;
comboBoxFinJCSpares1.DisplayMember = "DisplayMember";
comboBoxFinJCSpares1.ValueMember = "PartID";
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
}
Thanks guys, the "SelectedChangeCommitted" option suggested by Marcel Hoekstra solved my problem.

DataGridView bound with binding list displays blank rows

I have table in my database stored in SQL Server 2012 and through this table I am iterating and adding new object in my binding list. This list is then set as datasource for my DataGridView.
As I understand, the DataGridView should create columns and fill the rows with data, but when I run the build, I only see blank rows. Their count is matching the count of rows in table and I also debugged with breakpoints so I have determined that I really have my datasource filled with data, but I cannot figure those blank rows out.
This is method I use for creating dataset and filling the binding list
public void selectCars()
{
string connString = #"Data Source=POHJOLA\SQLEXPRESS;Initial Catalog=BlueCars;Integrated Security=True";
using (SqlConnection connection = new SqlConnection(connString))
{
connection.Open();
string query = "SELECT * FROM Car ORDER BY CarID ASC";
SqlCommand command = new SqlCommand(query, connection);
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
using (DataSet result = new DataSet())
{
adapter.Fill(result);
foreach (DataRow row in result.Tables[0].Rows)
{
carsList.Add(new Car(Convert.ToInt32(row[0]), row[1].ToString(), row[2].ToString(), row[3].ToString(), Convert.ToDecimal(row[4]),Convert.ToInt32(row[5]),row[6].ToString(),row[7].ToString() ));
}
}
}
}
This is my initialization
public managerCarForm()
{
InitializeComponent();
selectCars();
carsGrid.DataSource = carsList;
}
Also I should probably add, that I created columns manually in designer and set datanameproperty to parameters of the car class
I am not getting any exception or error here..
Thanks very much in advance!
I came across the exact same problem in VB.
I Found out that the solution was this:
(I´ll just write my code in VB you can translate it).
Before setting the DataSource of the grid, you should Clear the grid out.
carsGrid.DataSource = Nothing
carsGrid.Rows.Clear()
carsGrid.Columns.Clear()
Then set your grid DataSource as usual. In My case:
carsGrid.DataSource = GetEmptyObject._Get()
Hope it Helps.
foreach (DataRow row in result.Tables[0].Rows)
{
carsList.Add(new Car(Convert.ToInt32(row[0]), row[1].ToString(), row[2].ToString(), row[3].ToString(), Convert.ToDecimal(row[4]),Convert.ToInt32(row[5]),row[6].ToString(),row[7].ToString() ));
}
Please check your carList by applying a breakpoint after foreach loop to verify it contains at least a single data row. And also check your query.
If your application is an ASP.NET
try to modify your code as below..
public managerCarForm()
{
InitializeComponent();
selectCars();
carsGrid.DataSource = carsList;
carsGrid.Databind();
}
Normally this happens when you have manually added the columns in design time.
Or you have AutoGenerateColumns = false;
If you use AutoGenerateColumns = true; the columns will be/should be auto generated.
To solve this:
Right click on the grid -> Edit Columns.
Go to property: DataPropertyName
Set that to the variable name that you bind to (the table column name in your case).
(You say you have done that, but the value here should exactly match what you have in your list. I have made a DTO class and via a loop I have populated a List of my own and set the names to match the properties of that DTO. This should solve it for you.)

Categories