I am working on an application which has DataGridView bound to a database.
Done simply by setting datasource property of datagridview.
As now I have to work on search feature so
I get the data in a new data set and tried to bind the data source with the newly created dataset.
gridviewobj.datasource = newdataset;
but the data grid always appear as empty.
my data set contents the appropriate data.
still the problem arrives.
Please help
To show the data we have to bind it as well after setting up the datasource (as "Naveen" mentioned in the comment):
gridviewobj.datasource = newdataset;
gridviewobj.DataBind();
Hope it helps you.
private void GridBind(string StrQry="")
{
string Qry = string.Empty;
//StrQry = "Select * from tbl_Emp where Dept='Acc'";
if (StrQry != string.Empty)
{
Qry = StrQry;
}
else
{
Qry = "Select * from tbl_Emp";
}
Conn();
Cmd = new SqlCommand(Qry,con);
da = new SqldataAdapter(cmd);
da.fil(dt);
if (dt != null && dt.Rows.Count > 0)
{
gridviewobj.datasource = dt;
}
}
You may have to set the Table index, This will work if the columns are created dynamically.
gridviewobj.datasource = newdataset.Tables[0];
If you have already created the Grid columns manually through the Grid Edit wizard then you will have to go to properties of each column and set the DataPropertyName to relevant Database table column name to bind.
Related
I'm populating a DGV with data from a database and everything works fine, with the exception of when 0 rows are returned to the DataTable that populates the DGV. And I'm not sure how exactly to handle that situation, which I do need to allow for due to the program requirements.
Here's the Form code that calls the data binding method:
public void PopulateDgvCategories()
{
string companyFilter = cboSelectCompany.Text;
string categoryFilter = cboSelectCategory.Text;
db categoriesData = new db();
if (categoryFilter == "All Categories")
{
string catsQuery = "SELECT id, category, old_value, old_desc, new_value, new_desc, reference1, reference2 " +
"FROM masterfiles.xref WHERE company_name = #company ORDER BY category, old_value";
this.dtCategories = categoriesData.GetDgvData(catsQuery, companyFilter, categoryFilter);
}
else
{
string catsQuery = "SELECT id, category, old_value, old_desc, new_value, new_desc, reference1, reference2 " +
"FROM masterfiles.xref WHERE company_name = #company and category = #category ORDER BY old_value";
this.dtCategories = categoriesData.GetDgvData(catsQuery, companyFilter, categoryFilter);
}
// Need to check this.dtCategories.Rows.Count
// If 0, then need to figure out how to handle that
dgvCategories.DataSource = this.dtCategories;
dgvCategories.Columns[0].Visible = false;
dgvCategories.Rows[0].Cells[0].Selected = false;
}
And here's how I'm retrieving the data and filling the DataTable:
public DataTable GetDgvData(string selectQuery, string companyFilter, string categoryFilter)
{
using (NpgsqlConnection conn = new NpgsqlConnection(connString))
using (NpgsqlCommand cmd = new NpgsqlCommand(selectQuery, conn))
{
cmd.Parameters.Add(new NpgsqlParameter("company", companyFilter));
if (categoryFilter != "All Categories") cmd.Parameters.Add(new NpgsqlParameter("category", categoryFilter));
DataSet ds = new DataSet();
conn.Open();
using (NpgsqlDataAdapter da = new NpgsqlDataAdapter(cmd))
{
da.Fill(ds);
}
conn.Close();
return ds.Tables[0];
}
}
It is possible for the categoryFilter variable to cause the query to return 0 rows.
What is the best way to handle that? I'm thinking manually create the DGV with just the header row (column names) and display a MessageBox saying no rows were returned. Is that possible/feasible and would it be the best way to handle that?
There is absolutely no problem binding a datatable with zero rows - it will have a set of columns of the correct types regardless and will autocreate columns if the AutoGenerateColumns property is true
The problems come simply because you're trying to access a datagridview cell at 0,0 without making sure it exists, so you could put:
dgvCategories.DataSource = this.dtCategories;
dgvCategories.Columns[0].Visible = false;
it(dtCategories.Rows.Count > 0)
dgvCategories.Rows[0].Cells[0].Selected = false;
But you should just take this line out completely - it doesn't do anything anyway; it doesn't hide the blue selection highlight in the top left and a freshly bound datagridview's top left cell is already Selected=false so you're not achieving anything other than an exception with this line of code
If you want to hide the blue selection highlight when a DGV isn't focused, set the cell's Style.SelectionBackColor to be the same as its Style.BackColor, but do set it to something visible when the user focuses the grid or they will struggle to understand why they can't make that cell highlighted.
If you want to remove the ghost row that allows you to add new values, set AllowUserToAddRows to false
If you want to let the user know there were no rows from a recent search, place a label on top of the DGV with a "Your search 'whatever' returned no results" and set its visibility depending on whether there are rows:
lblNoResults.Text = $"Your search '{categoryFilter}' returned no rows";
lblNoResults.Visible = dtCategories.Rows.Count == 0;
Finally, you don't need to use a DataSet when all you want is a DataTable. A datadapter can fill a datatable; there is no need to go to the extra wasted effort of using a dataset - it's like using a List<string> and accessing it's 0th element when all you want is a string. You also don't need to open/close the connection - dataadapter knows how to do this itself. It is intelligent enough to not close a connection opened elsewhere (in case there is a transaction in progress):
DataTable dt = new DataTale();
using (NpgsqlDataAdapter da = new NpgsqlDataAdapter(cmd))
{
da.Fill(dt);
}
return dt;
I'm trying to bind a DGV to a particular table but don't want to have it display the data that is in the table (only using it for insert queries) but I cannot figure out how to actually accomplish this in C#. Here is the code I have (but again, I don't want any data to be shown, just the column names, so just ignore the select query, it's there to explain what I want fetched).
private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
{
if (tabControl1.SelectedTab == tabControl1.TabPages["tabPage1"])
{
// set the data source and bind to childrens table
this.dbcmd = this.dbconn.CreateCommand();
this.dbcmd.CommandText = "SELECT first_name, last_name, birthday, email FROM children";
this.dt = new DataTable();
this.da = new SQLiteDataAdapter(this.dbcmd); // don't want this either I think
this.da.Fill(this.dt); // this I know I do not want
this.bindingSource = new BindingSource();
this.bindingSource.DataSource = this.dt;
dataGridViewChildren.DataSource = this.bindingSource;
}
}
Does this make any sense? I'm sorry if I didn't provide enough information, I will try to provide more if more is needed.
Appreciate any help,
Thanks!
You can set the DataTable's DefaultView's Row Filter property to only show user added rows.
I did this by adding a column to the DataTable that sets all of your queried rows to false. Then any time a row is added to the DataTable from there on it gets set with true. I set the new column to not be displayed.
dt.Columns.Add(new DataColumn("UserAdded", typeof(bool)));
foreach (var row in dt.Rows.Cast<DataRow>())
row["UserAdded"] = false;
bindingSource.DataSource = dt;
dataGridViewChildren.DataSource = bindingSource;
dataGridViewChildren.Columns.Cast<DataGridViewColumn>().Last().Visible = false;
dt.DefaultView.RowFilter = "UserAdded = true";
dt.TableNewRow += (s, e) =>
{
e.Row["UserAdded"] = true;
};
When the insert button is clicked you can get the rows the user added with...
var rows = dataGridViewChildren.Rows.Cast<DataGridViewRow>()
.Where(r => !r.IsNewRow);
I need to know the original type of each column in my DataGridView.
It is bound with a dynamic SQL select, say, "SELECT * FROM artists;"
I want to add a form view of the data above the grid and am programmtically creating Labels and TextBoxes and then some to hold the fields. I add them to a FlowLayoutPanel but I would like to adapt the sizes, especially the multiline property and the height to accomodate long comment and description fields of say 200-500 characters.
All I found when looking into the text columns was datatype string.
I know I can look up the columns by querying the systables, but it would be nice to find the original datatype a bit closer than that; also I'm using MYSQL atm, and a solution that doesn't need to query the database would hopefully also be DBMS independent.
Edit 1
I fill the DGV with nothing fancy:
DBDA = new MySqlDataAdapter(sql, DBC);
MySqlCommandBuilder cb = new MySqlCommandBuilder(DBDA);
DBDS = new DataSet(ddlb_tables.Text);
DBDA.FillSchema(DBDS, SchemaType.Mapped); //<- This was the missing piece of code!!
DBDA.Fill(DBDS, ddlb_tables.Text);
dataGridView1.DataSource = DBDS;
dataGridView1.DataMember = ddlb_tables.Text;
Edit 2
With the help of the accepted answer (DBDA.MissingSchemaAction) I could solve my problem. Here is the resulting function in its first, raw version:
public int getColumnSize(DataGridViewColumn dc)
{
try
{
DataGridView DGV = dc.DataGridView;
DataSet DS = (DataSet)DGV.DataSource;
DataTable DT = DS.Tables[0];
DataColumn DC = DT.Columns[dc.Name];
return DC.MaxLength;
} catch { }
return -1;
}
Not getting the original type is not a problem, as long as I know the length of the fields.
use the DataSet instead DataGrid:
foreach (DataColumn col in DBDS[ddlb_tables.Text].Text.Columns)
{
if (col.DataType == typeof(string))
{
var len = col.MaxLenght;
...
}
}
EDIT:
You may need to add the following line before filling:
DBDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;
Source: The DataAdapter.Fill method does not set all of the properties of the DataTable and DataColumn objects
EDIT 2:
Or for result sets without a key:
DBDA.FillSchema(DBDS, SchemaType.Source);
Or:
DBDA.FillSchema(DBDS, SchemaType.Mapped);
i have this code for fill combo-box
SQL = "SELECT DISTINCT Name,Num FROM MyTbl order by Name";
adp = new OracleDataAdapter(SQL, Conn);
adp.Fill(dsNa, "MyTbl");
adp.Dispose();
comFna.DataSource = dsNa.Tables[0];
comFna.DisplayMember = dsNa.Tables[0].Columns[0].ColumnName;
comFna.ValueMember = dsNa.Tables[0].Columns[1].ColumnName;
but after inserting new Name - i dont see hem
and after i run this code again - i see duplicity records (only in the combobox)
how to solve this ? (i work on C# Winforms)
thank's in advance
when you add new name to database you have two choices:
1) create a new item with given name (and num value) and insert it into combobox items collection.
2) re-load combobox from database (which you are using)
the only problem is that you need to clear combobox items or set its datasource to null before re-binding it.
adp.Dispose();
comFna.DataSource = null; //ADD THIS LINE HERE OR comFna.Items.Clear();
comFna.DataSource = dsNa.Tables[0];
comFna.DisplayMember = dsNa.Tables[0].Columns[0].ColumnName;
comFna.ValueMember = dsNa.Tables[0].Columns[1].ColumnName;
comFna.Items.Clear();
before filling your comboBox, use this code to remove old items, and then re-fill it.
Using c# .net 2.0 , I want to bind a textbox to a specific row of my table. In Example :
Table Person
ID NAME PRENOM SPECIAL_CATEGORY
1 BOB BOB mex
2 AL AL tot
3 PO PO pap
I want to bind my textbox on the field name where the row contains special_categeory = 'tot'.
Is it possible? or I need to create a Datarow for this row and binding it.
Assuming you're talking about Winforms and you have your data source as a component on your form already, this is fairly simple.
Drag a new BindingSource onto your form and set its data source to be whatever your existing data source is. You can then specify a filtering expression in the new BindingSource's Filter property in the designer. Bind your TextBox to your new BindingSource and you're all set.
Doing this manually (without the designer) is only marginally more complicated.
BindingSource newSource = new BindingSource();
newSource.DataSource = yourExistingDataSource;
newSource.Filter = "special_categeory = 'tot'";
textBox.DataBindings.Add("Text", newSource, "DataMember");
You should be able to bind via...
myNameTextBox.DataBindings.Add( "Text", MyTable, "NAME" );
myPrenomTextBox.DataBindings.Add( "Text", MyTable, "PRENOM" );
mySpecial_CategoryTextBox.DataBindings.Add( "Text", MyTable, "SPECIAL_CATEGORY" );
I actually have a framework that scrolls through all controls, and if they match a column name in a given table, they immediately bind themselves like above.
Then, when you scroll the grid, it should also refresh the individual text controls in your form too.
If there is some binding that needs to be done, you can follow this pattern:
DataView dv = new DataView(MyTable);
dv.RowFilter = "SPECIAL_CATEGORY = 'tot'";
GridView1.DataSource = dv;
GridView1.DataBind();
But I don't think you bind to a TextBox? You can set the Text property like:
foreach(DataRow dr in MyTable.Rows)
{
if (dr["SPECIAL_CATEGORY"] != DBNull.Value &&
dr["SPECIAL_CATEGORY"].ToString() == "tot")
{
myTextBox.Text = dr["NAME"].ToString()
break;
}
}
I'm going to assume it's Winforms and this is how you can do it:
myTable.DefaultView.RowFilter = "SPECIAL_CATEGORY = 'tot'";
this.textBox1.DataBindings.Add("Text",myTable.DefaultView,"Name");