I have this query select distinct b.Name Project, a.Name Field from viewBatchClassIndexFields a inner join BatchDef b on a.DocumentBatchDefID = b.BatchDefID where b.Name = #projecto order by 1
What this does is, grabs the projectName and with that it return indexFields that are needed the catch is that almost every projectName as different index fields as a return, my question is.
How can i populate a gridView without knowing before hand what fields i will have.
there is nothing stopping you from having the gridview auto generate the columns for you. In fact, if you do nothing, that is the default!!!
So, I assume you used the project->settings, and setup a valid connection to the database. Ok, so now we drop a gridview onto the web page, say like this:
<asp:GridView ID="GridView1" runat="server"></asp:GridView>
ok, now, here is our code to fill the grid view:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
// load up our grid
using (SqlCommand cmdSQL = new SqlCommand("SELECT TOP 10 * from tblHotels ORDER BY HotelName ",
new SqlConnection(Properties.Settings.Default.TEST4)))
{
cmdSQL.Connection.Open();
GridView1.DataSource = cmdSQL.ExecuteReader();
GridView1.DataBind();
}
}
So, no where did I specify any column names.
Output:
So, you can shove/use/have any query you want in above - the grid will use the column names from the data source. As a result, you can quite much use any data source (any sql query - even ones with joins) for that data source.
You can also of course load the query results into a datatable, and then of course loop the column names, and add them to the columns to the gridview, but if you don't set AutoGeneraateColumns = false (then the grid will auto generate columns for you).
Related
I'm supposed to create a master-detail form and I must add the details straight on the datagridview which is binded to the database. So I have a form with two tables: intrari (master) and intrari_detaliu (detail).
When I use the binding navigator to select a row in table intrari which is the parent table, I also get the corresponding details in table intrari_detaliu. I use text boxes/combox to add value in table intrari.
So how do I insert values straight into data grid view?
image for the form visual structure
What I tried:
First try:
DataClasses1DataContext db = new DataClasses1DataContext();
private void btnadd_Click(object sender, EventArgs e)
{
int ID; int id_intrari = 0; int id_produs = 0; decimal cantitate = 0; decimal valoare = 0;
for (int i = 0; i <tbl_intrari_detaliuDataGridView.RowCount - 1; i++)
{
if row
ID = Convert.ToInt32(tbl_intrari_detaliuDataGridView.Rows[i].Cells[0].Value.ToString());
id_intrari = Convert.ToInt32(tbl_intrari_detaliuDataGridView.Rows[i].Cells[1].Value.ToString());
id_produs = Convert.ToInt32(tbl_intrari_detaliuDataGridView.Rows[i].Cells[2].Value.ToString());
cantitate = Convert.ToDecimal(tbl_intrari_detaliuDataGridView.Rows[i].Cells[3].Value.ToString());
valoare = Convert.ToDecimal(tbl_intrari_detaliuDataGridView.Rows[i].Cells[4].Value.ToString());
var st = new tbl_intrari_detaliu
{
ID= ID,
id_intrari = id_intrari,
id_produs = id_produs,
cantitate = cantitate,
valoare = valoare,
};
db.tbl_intrari_detalius.InsertOnSubmit(st);
db.SubmitChanges();
}
}
but this first copies every row above and then it adds the new row. E.g.: I already have inserted row A and B, and when I want to insert row C, it first inserts row A and B again and inserts then C.
Second try:
public partial class Intrari2 : Form
{
SqlConnection con;
SqlDataAdapter adap;
DataSet ds;
SqlCommandBuilder cmbl;
private void Intrari2_Load(object sender, EventArgs e)
{
con = new SqlConnection();
con.ConnectionString = #"Data Source=DESKTOP-KVMM566;Initial
Catalog=MyDatabase;Integrated Security=True";
con.Open();
adap = new SqlDataAdapter("select ID,id_intrari,id_produs,cantitate,valoare from tbl_intrari_detaliu", con);
ds = new System.Data.DataSet();
adap.Fill(ds, "tbl_intrari_detaliu");
tbl_intrari_detaliuDataGridView.DataSource = ds.Tables[0];
this.tbl_intrari_detaliuTableAdapter.Fill(this.myDatabaseDataSet.tbl_intrari_detaliu);
this.tbl_IntrariTableAdapter.Fill(this.myDatabaseDataSet.tbl_Intrari);
//Add button------------
private void btnadd_Click(object sender, EventArgs e)
{
cmbl = new SqlCommandBuilder(adap);
adap.Update(ds, "tbl_intrari_detaliu");
//the Fill method doesn't work anymore because of the code above
this.tbl_intrari_detaliuTableAdapter.Fill(this.myDatabaseDataSet.tbl_intrari_detaliu);
}
}
This one updates rows correctly, but when I select a row in table intari, I don't get the corresponding details (according to the id) in table intrari_detaliu. I get the details for all rows in the parent table. I know it's because of the code I added to select the data from table using SqlAdapter, but the code doesn't work without that statement.
So, I need to insert/update/delete a selected row from "intrari_detaliu" and still be able to get the corresponding details when I select a row in the parent table "intrari".
Can you help me, please?
It's so much easier than that. Throw all that code away (genuinely, all of it). Here is a demo using two of my test tables. 1 Car (parent) has many Clowns (child)
Here's how your data (should) get into your parent grid. You have a query in your TA that selects stuff based on something you want to search by, eg Name:
You give the queries GOOD NAMES, not just Fill - one day you'll have many queries, don't do Fill, Fill1, Fill2. Name them well now:
In your child tableadapter you provide a query that does a lookup by Parent ID:
Or you do a query that looks up children of the same thing you just made a parent query for, like CarName here:
Or you can do both/more/whatever. You can have many queries per TA:
To get grids onto your form you drag them out of Data Sources (View menu, Other Windows). This will do all the data binding setup for you; you can examine how visual studio has done it if you ever want to replicate it manually; the parent grid binds through a binding source, to the table in the dataset. The child grid binds through a binding source to a data relation on the parent binding source
To get related data behavior you drag the CHILD NODE Clowns, not the top level Clowns out of data sources
In your code, to fill the grids with data you just actually fill the tables; the grids will update themselves. You must fill the parent first, then the child. You fill the child either using the query that selects a lot of children based on the parent criteria (like my ...ByCarName),
this.carsTableAdapter.FillByCarName(this.dataSet1.Cars, "Billy"); //fill parent first
this.clownsTableAdapter.FillByCarName(this.dataSet1.Clowns, "Billy"); //then fill the children by the same
or you can enumerate the parent after you fill, and fill the children by the parent ID (like my ...ByCarId does):
this.carsTableAdapter.FillByCarName(this.dataSet1.Cars, "Billy"); //fill parent first
clownsTableAdapter.ClearBeforeFill = false; //turn this off otherwise every call to FillBy.. erases the previous rows
foreach (var r in this.dataSet1.Cars) //for each parent
clownsTableAdapter.FillByCarId(this.dataSet1.Clowns, r.CarId); //fill the children
Saving
Dragging the grids wrote this:
this.Validate();
this.carsBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.dataSet1);
Add a line:
this.Validate();
this.carsBindingSource.EndEdit();
this.clownsBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.dataSet1);
That is all you need to do; click the button that runs that code; the tableadapter manager saves any changes you made to the data set, like adding a new row by writing in the bottom of the grid...
..or if you did it in code:
Regardless how it got there, it's a new row with the RowState of Added
When the tableadaptermanager.UpdateAll is called, or if you call an individual tableadapter.Update:
carsTableAdapter.Update(this.dataset1.Cars); //update doesn't just UPDATE, it runs INSERT and DELETE too
then the changes you made locally are saved. If someone else changed the data while you were editing it, and you have Optimistic Concurrency turned on (see above "Refresh the.." in the screenshot above) then you get an exception at the point of save. You can choose what to do to and write code that overwrites the new data, merges it, or discards the changes; ask the user what they would like to do
Note, if the DB is calculating your parent and child ID values, right clic on the relation line between your datatables, and ensure that Update is set to cascade:
This way when you add a new car and two new related clowns, and the car has -1 ID (generated locally by the dataset, pre-save), and the clowns use it too:
Then when the DB calculates the real ID, and "Refresh the dataset" option...
... causes the new ID to be retreived:
Then the changing of CarId -1 in the parent to e.g. 15 (what the DB calculated) causes the child Clowns' CarIds to be updated automatically too so the relation is preserved
TableAdapter.Update will save every kind of change; edits, deletions and inserts (new rows)
Actually I am copying rows from one datagrid to another on DataGridView Double Click Event, and it's going well. The code is here:
//Void App
void AddProducts(int ProdID, string Name, string ProductCode, int RetailPrice, int SalePrice, string BrandName, string Category, int QTY)
{
string[] row = { Convert.ToUInt32(ProdID).ToString(), Name, ProductCode,
Convert.ToInt32(RetailPrice).ToString(), Convert.ToInt32(SalePrice).ToString(), BrandName, Category, Convert.ToInt32(QTY).ToString()};
dgViewProductsToSell.Rows.Add(row);
}
//Code
private void dgViewProducts_MouseDoubleClick(object sender, MouseEventArgs e)
{
string Name1 = this.dgViewProducts.CurrentRow.Cells["Name"].Value.ToString();
int ProdID = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["ProdID"].Value);
string Name = dgViewProducts.CurrentRow.Cells["Name"].Value.ToString();
string ProductCode = dgViewProducts.CurrentRow.Cells["ProductCode"].Value.ToString();
int RetailPrice = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["RetailPrice"].Value);
int SalePrice = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["SalePrice"].Value);
string BrandName = dgViewProducts.CurrentRow.Cells["BrandName"].Value.ToString();
string Category = dgViewProducts.CurrentRow.Cells["Category"].Value.ToString();
int QTY = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["QTY"].Value);
AddProducts(Convert.ToInt32(ProdID), Name, ProductCode, Convert.ToInt32(RetailPrice), Convert.ToInt32(SalePrice), BrandName, Category, Convert.ToInt32(QTY));
}
How I can check duplicate entries before copying the rows? So the 2nd datagridview could avoid duplicate entries.
I'm going to start off with this scrappy test app:
Don't worry that it's a screenshot of code - that's just for information purposes of how it came to be that I generated a datagridview with some data in it. This is how do "do it properly" - you keep your data in a DataTable and you use a grid to show it
The next step: we are going to make a strongly typed dataset, datatable, set its primary key, put it on the form along with a datagridview it is bound to, and we are going to fill it uniquely by double clicking the existing grid. I modeled the existing grid more like you have done. In reality I would make BOTH these grids be based on a strongly typed data table, but I wanted to show you you didn't have to, and my advice for making a strongly typed datatable can fit in with your existing idea of stuffing data into a datagridview directly, until you're ready to change over
Add a new DataSet type item to your project. Right click the project, Add.. New Item:
Give it a nice name. Nothing worse than code full of Form1, DataSet1, GridView3, Button27
When it's added, double click it to open the design surface. Right click the surface and add a new datatable:
Give it a nice name, right click it repeatedly and add columns for all you want, Name, Code, Price etc:
Don't forget to give them a datatype too, so not everything is a string!
You said you want to be unique by name so.. Click in the grey bit next to Name so the row goes all blue, then right click and choose Set primary key
Save it all, close the dataset designer, go to the forms designer, click the VIEW menu, go to OTHER WINDOWS >> DATASOURCES. You can also press Shift+Alt+D
Open the DATA SOURCES panel, find the grid node of your datatable (whatever you called it) and drag it onto the form
A datagridview, connected to your custom datatable has appeared, together with some new things at the bottom. You can delete the bindingnavigator:
(and rename the dataset instance so it has a nicer name than xxxxDataSet1)
That's all the setup we need for now to set up the receiver datatable, and grid. Let's edit the event handler for the mouse double click. I jiggled things around a bit and added another feature as a demonstration, that if the row IS there we can update it, otherwise we add it:
private void _dataGridViewSrc_MouseDoubleClick(object sender, MouseEventArgs e)
{
//my source datagrid is bound to a datatable. I use this to retrieve the current row related
//to the row in the grid that was double clicked
DataRow sourceRow = (_dataGridViewSrc.CurrentRow.DataBoundItem as DataRowView)?.Row;
if(sourceRow == null)
return;
//because we made Name the primary key, the strongly typed datatable has a FindByName method
//we pass it the string Name from the source datatable row (a grid row cell value in your case)
NiceNameDataSet.UniqueProductsRow destRow = _niceNameDataSet.UniqueProducts.FindByName((string)sourceRow["Name"]);
//FindByName returns NULL if the row wasn't found
if(destRow == null)
{
//the row isn't there, so add it, using the data from the source row
_niceNameDataSet.UniqueProducts.AddUniqueProductsRow(
(string)sourceRow["Name"],
(string)sourceRow["Code"],
(double)sourceRow["Price"]
);
} else
{
//the row IS there, how about we update the fields using the row that was just clicked?
//this demonstrated how much nicer it is to work with a strongly typed dataset/datatable
//because all the columns have proper Properties, like row.Code, with proeprt datatypes
//like string and double, rather than having to be referred to with a string name like
//row["Code"] and having to be cast from object to string, double all the time: messy
//and error prone
destRow.Code = (string)sourceRow["Code"];
destRow.Price = (double)sourceRow["Price"];
}
}
I changed the prices and codes a bit to demo this other featuer. Now you can double click either bread row as much as you like and you only get one row in the destination grid, and it changes its values back and forth:
You can create an object which represents each row with properties for each column. For this object you can create an public bool Equals(object obj) method.
With the object you can compare already read objects with newly read objects. Either manually or by using something Contains or similar methods which are part of List<> and Dictionary<> classes.
It all depends on how much data you have and which line you consider to be equal to another line. Is it equal / a collision if the product ID is a duplicate or do all properties also have to match
Each row should have a primary key, usually an ID. I am assuming this is the case for you.
Second assumption: both datagridview controls are bound to datatables/datasets or binding sources.
So, when the user selects a row in the grid, retrieve the underlying datarow. This can be done using the databounditem function. Then you can fetch the ID or primary key.
Then compare the two datatables. This is more efficient and safer than accessing UI controls. There are different ways to check that a record already exists in a datatable, for example the select function. Another option is using LINQ.
Do not try to update the second datagridview directly, instead you add a record to its underlying datatable, and you let the datagridview update itself.
Your code seems to be unsafe. What happens if the user double-clicks on the edges of the grid ? The current row could be -1. You need to add a check.
You should also test what happens if the user sorts the columns in the datagrid or drag the columns to change the display order.
To sum up I strongly advise to use datatables, even if you are not reading from or saving to database.
You can use the following code to remove duplicate entries before copying the datagridview.
Code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
DataTable table = new DataTable();
table.Columns.Add("Name");
table.Columns.Add("Id");
table.Columns.Add("Age");
table.Rows.Add("test1",1001,22);
table.Rows.Add("test1", 1001, 22);
table.Rows.Add("test2", 1002, 23);
table.Rows.Add("test3", 1003, 24);
dataGridView1.DataSource = table;
}
private void dataGridView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
DataTable dt = (DataTable)dataGridView1.DataSource;
dt = dt.DefaultView.ToTable(true);
dataGridView2.DataSource = dt;
}
}
Result:
I don't know if I correctly understand your question but maybe this will help
before adding into my gridview I already checked the possibility of duplicate
//Validate duplicate data b4 adding to gridview
for (int i = 0; i < dataGridView2.Rows.Count; i++)
{
if (textBox1.Text == dataGridView2.Rows[i].Cells[1].Value.ToString())
{
MessageBox.Show("Product already on the list, if you wish to add this product click the product name and edit the quantity", "System Message", MessageBoxButtons.OK, MessageBoxIcon.Information);
textBox1.Text = "";
textBox2.Text = "";
textBox1.Focus();
return;
} else { }
}
then pass the datagridview1(form1) to datagridview2(form2)
List<PurChaseRcpT> cdgv = new List<PurChaseRcpT>();
foreach (DataGridViewRow Item in dataGridView2.Rows)
{
cdgv.Add(new PurChaseRcpT {
Particular = Item.Cells[0].Value.ToString(),
Qty = Item.Cells[2].Value.ToString(),
UM = Item.Cells[3].Value.ToString(),
Price = Item.Cells[4].Value.ToString(),
Total = Item.Cells[5].Value.ToString()
});
}
FrM_SubChange ChangeFrm = new FrM_SubChange();
ChangeFrm.dataGridViewPassed = this.dataGridView2;
ChangeFrm.TempVal = cdgv;
ChangeFrm.Show();
hope it help..
I have a c# code line as,
using (SqlDataSource sqlds = new SqlDataSource(ConnectionString(), SelectCommand()))
{
drop1.DataSource = sqlds;
drop1.DataTextField = "UserName";
drop1.DataBind();
}
now it's not populating my dropdownlist,
<asp:DropDownList id="drop1" runat="server" />
so I want to check if sql is returning data or not
if i put line break, I am not sure how to find out if sql is returning data, I am using using select statement and connection string for gridview and it works but not with drop down list
Be sure you have your sqlquery into select command then you need convert you
sqldatasource select command into dataview.
string query = "select yourfield from yourtable";
using (SqlDataSource sqlds = new SqlDataSource(conn.ConnectionString, query))
{
System.Data.DataView dv = (System.Data.DataView)sqlds.Select(DataSourceSelectArguments.Empty);
if (dv.Count > 0)
{
DropDownList1.DataSource = sqlds;
DropDownList1.DataTextField = "yourfield";
DropDownList1.DataBind();
}
}
You should be able to put a breakpoint on drop1.DataSource = sqlds; and then move your mouse over sqlds and it should show you how many rows are contained in the DataSource.
your way of binding datasource to the dropdown is correct and same thing is working for me.
Possible errors can be
in the connectionString. Verify if it is correct.
in the Select Query. Verify if the SelectCommand() methods returns correct sql query.
use Selected event of the SqlDataSource to verify whether it returned any row i.e
sqlds.Selected += new SqlDataSourceStatusEventHandler(sdl_Selected);
where sql_Selected is:
void sdl_Selected(object sender, SqlDataSourceStatusEventArgs e)
{
var a = e.AffectedRows;
}
as a Side note - make sure your select query doesn't contain any string concatenation prone to sql injection. i.e. SELECT UserName from [TableName] where certainCol ="+ variable.
Don't do it
provide a sql parameter instead, and add the SelectParameters to your SqlDataSource
I have made a basic program to add values to a dataSet and display it to a dataGridView:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DataTable table1 = new DataTable("People");
table1.Columns.Add("id");
table1.Columns.Add("Name");
table1.Columns.Add("Age");
table1.Rows.Add(1, "Jack", 18);
table1.Rows.Add(2, "Tim", 18);
DataSet set = new DataSet("SetPeople");
set.Tables.Add(table1);
dataGridView1.DataSource = set;
dataGridView1.Update();
}
}
When I try it out nothing seems to happen. The dataGridView remains blank. Any idea where I am going wrong?
try this
dataGridView1.DataSource = table1;
you don't need a Ds for just showing a data table in a Gridview
Massimiliano Peluso is correct. The GridView will reference a"Table", but more specifically, when using ADO.NET in a Disconnected fashion you will be filling the GridView with DataColumn objects that are part of a DataTable object. You will also want to bind your dataTable to the GridView.
A bit of Detail:
ADO.Net's DataSet construct allows you to represent your database in a "table" like manner and allow those tables to share references. All of this comes at the cost of additional memory overhead, but if this is not going to be a highly scalable applicaiton and you want to give the users the ability to edit rows without having to go to the database every time, DataSet is a good option.
If you are not using the featuers of DataSet (e.g. table relationships) you can save yourself a little overhead by just using DataTable objects and populating them.
To answer your questions:
A GridView expects to recieve a DataTable as a data source. That table can contain several columns (which will fill the columns of the grid). You can write the following code to specifically access your data table:
dataGridView1.DataSource = set.Tables["table1"]; // or by index if you prefer as there are several overloads.
Additionally, I would bind the data by adding the following line of code after the one perscribed above:
dataGridView1.DataBind();
The fact you are missing your DataBind() method call is part of your issue.
There is a very good example at C sharp corner site: Example
You could also do this:
dataGridView1.DataSource = set;
dataGridView1.DataMember = set.Tables["People"].TableName;
dataGridView1.Update();
I have a very simple scenario but poor experience in this area and googling around didn't help much.
Consider a classic ASPX page with C# code behind. Let's say I have a list of DataTables (or a DataSet with several tables). I need the means to display all tables using one DataGrid per table.
I tried binding entire DataSet to DataGrid but it displayed only the first table.
Something tells me I should be using a Repeater in conjunction with DataGrid but I need help with this or a totally different (better) alternative.
This is an example using dynamic controls:
ASPX
<asp:Panel runat="server" ID="myPanel" Width="100%">
</asp:Panel>
<asp:Label ID="lblMessage" runat="server" />
<asp:Button Text="Just post" runat="server" />
Code behind
protected void Page_Init(object sender, EventArgs e)
{
var s1 = Builder<Product>.CreateListOfSize(5).Build();
var s2 = Builder<Order>.CreateListOfSize(9).Build();
var g1 = new DataGrid { Width = new Unit("50%"), DataSource = s1 };
var g2 = new DataGrid { Width = new Unit("50%"), DataSource = s2 };
this.myPanel.Controls.Add(g1);
this.myPanel.Controls.Add(g2);
}
protected void Page_Load(object sender, EventArgs e)
{
this.DataBind();
}
Output:
Note that the view state of each grid is kept among post backs
Take a look at this link:
http://msdn.microsoft.com/en-us/library/system.data.dataset.tables.aspx
If you are using a Dataset you can do something like:
MyGrid.DataSource = dataset.Tables[0]
MyGrid2.DataSource = dataset.Tables[1]
Then repeat for each table index within the grid e.g 1, 2, 3
I don't know what you want to show in all the tables, even if you will show all the tables how will you manage the heading of every table record. I think you need to first think what you want?
If you have every table same number of columns then its easy to maintain, do you know how to use union?
select x, y,z from table1
union
select x, y,z from table2
union
select x, y,z from table3
union
select x, y,z from table4
it will create just a single table result from all the four table and can be easily bind.
I don't know you need this or not but I tried to help you anyway :)