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).
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 quantity based information data grid view it has 3 columns of type text and 1 column of type check box, now this data grid view is filled with different item quantities and different expire dates for the same item from the inventory table whenever the user enters an item name.
The problem is whenever the item is selected and inserted in another data grid view using a button named as Add Item the tools used for data entry are cleared also the data grid view of quantity based information should be cleared, I tried this code but it erases the data grid view completely I just want the data retrieved from database only to be cleared and the headers of the data grid view still appear.
This codes are used in Add Item button
DataRow r = dt.NewRow();
r[0] = sBillItemBartxt.Text;
r[1] = sBillItemNametxt.Text;
r[2] = itemQuanttxt.Text;
r[3] = itemPricetxt.Text;
r[4] = itemTtlPricetxt.Text;
r[5] = expire;
dt.Rows.Add(r);
sBilldgv.DataSource = dt;
clearItemsText();
sBillTtlCostlbl.Text = (from DataGridViewRow row in sBilldgv.Rows where row.Cells[4].FormattedValue.ToString() != string.Empty select Convert.ToDouble(row.Cells[4].FormattedValue)).Sum().ToString();
sBillItemBartxt.ReadOnly = sBillItemNametxt.ReadOnly = false;
dtRes.Clear();
exDatedgv.DataSource = null;
exDatedgv.Rows.Clear();
exDatedgv.Columns.Clear();
They can be cleared nearly the same way as you add them (Without removing columns).
MyDataGridView.Rows.Clear();
This will target rows instead of columns.
I think your header is being cleared because of
exDatedgv.Columns.Clear();
Also if you only wish to remove the rows that are repeated, you might want to consider using a loop to check for the repeated row and remove that row only before adding a new one.
I would also tell you to use a BindingList with your datagridview but since one of your columns is a checkbox im not really sure how you could achieve this with a BindingList
It is unclear from your code what you are trying to do. Since you are using as DataTable I am not sure why the DataTable dtRes.Clear(); does not work as this will clear all the data and KEEP the column headers. When you set exDatedgv.DataSource = null; this will clear the rows and columns so the next two lines are superfluous. To get the DataGridView to clear as you describe… simply Clear the DataTable associated with that DataGridView. This will leave the headers intact, however after this "Clear" there will be no data in the table, so if you try to re-bind the table you just cleared, obviously it will be empty. If you do not want to remove the data from the table, then you will have to either set the headers yourself, create an empty table for this purpose or simply (not the best solution) create a copy from a master. Below I made a data bound DataGridView, then cleared it as described above with button 2, then re-set (re-bind) the DataGridView to a copy of the original table. This clears the DataGridView leaving the headers when pressing button 2, then re-sets the DataGridView to the original data when pressing button 3. Hope this helps.
private void button2_Click(object sender, EventArgs e) {
//dataGridView1.Columns.Clear(); <-- clears headers
//dataGridView1.Rows.Clear(); <-- will crash if data is bound
//dataGridView1.DataSource = null; <-- removes headers
dt.Clear(); // <-- Clears data and leaves headers, removes data from table!
}
private void button3_Click(object sender, EventArgs e) {
dt = masterTable.Copy(); // <-- Get a new table if it was cleared
dataGridView1.DataSource = dt;
}
I think it best I explain my scenario first.
I bring all my data back from a sql database, using SqlDataAdapters, within on transaction.
In an example, I have a college. I want open this college and add modules, and at the same time I wish to add students to these new modules.
These modules and students are saved to their respective DataTable, and the student table has a column relating to it's parent module, "moduleid".
My problem is that I need a way to save both of these in the same transaction, adding the new moduleid to it's child rows. I can create the new modules, and their own moduleid in it's datatable is updated, however when I now need to save the students to this module, I need to add it's moduleid, otherwise it's added to the database without one.
This is my effort so far but I feel I'm barking up the wrong tree.
DataTable dt_new_modules = ds_College.Tables["module"].GetChanges(DataRowState.Added);
da_modules.Update(ds_College.Tables["module"]);
ds_College.Tables["module"].AcceptChanges();
DataTable dt_added = ds_College.Tables["student"].GetChanges(DataRowState.Added);
if (dt_added != null)
{
if (dt_new_modules != null)
{
foreach (DataRow new_module in dt_new_modules.Rows)
{
foreach (DataRow updated_module in ds_College.Tables["module"].Rows)
{
if (updated_module.Equals(new_module))
{
foreach (DataRow new_student in dt_added.Rows)
{
if ((int)new_student["moduleid"] == (int)new_module["moduleid"])
new_student["moduleid"] = (int)updated_module["moduleid"];
}
}
}
}
}
da_student.Update(dt_added);
dt_added.AcceptChanges();
}
DataTable dt_modified = ds_College.Tables["student"].GetChanges(DataRowState.Modified);
if (dt_modified != null)
{
da_student.Update(dt_modified);
dt_modified.AcceptChanges();
}
I am trying to loop through all the added users and if the datarow is the same as the one before it was given it's new moduleid, then get the new id and give it to the user, however I feel there must be a more efficient way to do this.
If I get it right, your problem is with inserting child records for a parent module which was not yet inserted to the DB. I had somewhat the same issue, and using SqlCommandBuilder instead made it work.
Create SqlCommandBuilder (System.Data.SqlClient) objects for each table you are changing, passing the corresponding sqlAdapter as a parameter to the constructor.
It creates the INSERT, UPDATE and DELETE commands automatically, and will handle all the changes made in memory back to the database.
After the command builder objects are created, just call "Update" on the data adapter you had for the parent table (modules), and afterwards "Update" on the children table data adapter.
Hope this solves it.
I am trying to bind a table in an SQL database to a DataGridView Control. I would like to make it so that when the user enters a new line of data in the DataGridView that a record is automatically added to the database. Here is my current attempt...
BOMClassesDataContext DB = new BOMClassesDataContext();
Form_Load()
{
var mfrs = from m in DB.Manufacturers
select m;
BindingSource bs = new BindingSource();
bs.DataSource = mfrs;
dataGridView1.DataSource = bs;
}
dataGridView_CellValueChanged()
{
try
{
DB.SubmitChanges()
}
catch(Exception Ex)
{
MessageBox.Show(Ex.Message);
}
}
If I click the bottom empty row it automatically fills in the ID (identity) column of the table with a "0" instead of the next unused value. If I change that value manually to the next available then it adds the new record fine but if I leave it at 0 it does nothing. How can i fix this? In my LINQ to SQL classes the ID column of the table has the AutoGenerate property set to true.
You need to execute DB.SubmitChanges() when the user has finished.
With Linq To SQL, no changes are made to the underlying database until you do that.