I tried to update selected rows in DataGridView, but the result is strange, it always missing a row or another. The problem is when I click btnSettled button to set the settled date, then click btnUpdate to update the database, the result seems ok, but after click btnRefresh to refresh the DGV, there is always a missing row. Is that the problem on UpdateCommand or foreach loop? Please help me to solve this problem. Thank you.
before click btnSettle
after click btnSettled and btnUpdate
after click btnRefresh
My code as follows:
DataTable dtTrx = new DataTable();
SqlDataAdapter daTrx = new SqlDataAdapter();
DataSet dsTrx = new DataSet();
public Form1()
{
InitializeComponent();
getData();
}
private void getData()
{
string strConn = "Data Source=.\\xpw;Initial Catalog=MyStock;Integrated Security=True;";
SqlConnection conn = new SqlConnection(strConn);
conn.Open();
string sqlTrx = "SELECT TrxID, TrxDate,Ticker,Qty,Price,Type,AccID, SettledDate,BrokerUserID FROM Trx";
daTrx = new SqlDataAdapter(sqlTrx, conn);
SqlCommandBuilder cbTrx = new SqlCommandBuilder(daTrx);
daTrx.Fill(dsTrx, "trx");
conn.Close();
dtTrx = dsTrx.Tables["trx"];
dgvTrx.DataSource = dtTrx;
}
private void btnUpdate_Click(object sender, EventArgs e)
{
daTrx.Update(dsTrx, "trx");
}
private void btnRefresh_Click(object sender, EventArgs e)
{
dsTrx.Clear();
daTrx.Fill(dsTrx, "trx");
}
private void btnSettled_Click(object sender, EventArgs e)
{
foreach (DataGridViewCell c in dgvTrx.SelectedCells)
{
dgvTrx[7, c.RowIndex].Value = "2017/7/23";
}
}
First of all you need start using parameterized SQL queries.
Secondly I don't see a problem with your code, but you try this :
private void btnSettled_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow r in dgvTrx.SelectedRows)
{
r.Cells["SettledDate"].Value = "2017/7/23"; //use the column name instead of column index
}
this.BindingContext[dgvTrx.DataSource].EndCurrentEdit();
//the above line is added to improve the solution
//as per the link mentioned in the accepted answer
}
The reason behind this approach is that now even if you change the column position, you won't have to re-write the code to match the changes
As you are using SelectedCells, thus unless your mouse is dragged over to the last Cell it won't be added in the SelectedCell collection
Note: in r.Cells["SettledDate"].Value I assumed the column name is SettledDate
Finally I found the solution in :
Programmingly udpating selected rows misses the last one in dgv.DataSource.GetChanges()?
It only needs to end-edit the last row after foreach loop:
this.BindingContext[dgvTrx.DataSource].EndCurrentEdit();
Thanks again to #Nobody.
Related
i have one Datagridview and two combobox (related) When I click on dataGridView1_CellMouseClick cmbSehir.Text changes as I want. but cmbilce.Text does not change as I want!. Where do i make mistakes. I hope I made myself clear. Thanks for helping.
private void frmMusteriEkle_Load(object sender, EventArgs e)
{
GetSehir();
GetDatagridview();
}
private void GetSehir() {
db.connect();
db.SqlQuery("select * from iller");
DataTable dt = db.GeTDataTable();
DataRow dr = dt.NewRow();
dr["id"] = 0;
dr["sehir"] = "Seçiniz:";
dt.Rows.InsertAt(dr, 0);
cmbSehir.DataSource = dt;
cmbSehir.ValueMember = "id";
cmbSehir.DisplayMember = "sehir";
db.disconnect();
}
private void cmbSehir_SelectionChangeCommitted(object sender, EventArgs e)
{
if (cmbSehir.SelectedIndex != 0)
{
db.connect();
db.SqlQuery("select * from ilceler where il_id = ?");
db.command.Parameters.AddWithValue("#p", cmbSehir.SelectedValue);
DataTable dt = db.GeTDataTable();
cmbilce.DataSource = dt;
cmbilce.ValueMember = "id";
cmbilce.DisplayMember = "ilceler";
db.disconnect();
}
else
{
cmbilce.DataSource = null;
}
}
private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
cmbSehir.Text = dataGridView1.Rows[e.RowIndex].Cells[4].Value.ToString();
cmbilce.Text = dataGridView1.Rows[e.RowIndex].Cells[5].Value.ToString();
}
Without seeing what GetDatagridview method does, I will assume from the lines…
cmbSehir.Text = dataGridView1.Rows[e.RowIndex].Cells[4].Value.ToString();
cmbilce.Text = dataGridView1.Rows[e.RowIndex].Cells[5].Value.ToString();
that these combo boxes are related to the data contained in columns 4 and 5. If the combo boxes have the same data source as the DataGridView then it is possible to bind all three controls to the same DataSource. After binding all three components to the same data source, clicking on a cell in the grid will automatically change the combo boxes and vice versa… changing a combo box will change the selection in the grid. There is no need to wire up the CellMouseClick or SelectionChanged events to keep the controls in sync.
Another consideration is the cmbSehir_SelectionChangeCommitted method that fires every time the user changes the selection in the cmbSehir combo box. In this method, the code queries the data base and sets the combo boxes data source. This is fine, however, are you sure you want to query the database and refill the combo box EVERY time the user changes this selection? I am guessing one query would be sufficient, until new data is added, removed or changed.
The code below sets the DataSource for the combo boxes to the same data source of the DataGridView using different ValueMembers.
DataTable AllData;
private void Form1_Load(object sender, EventArgs e) {
AllData = GetDT();
dataGridView1.DataSource = AllData;
comboBox1.DataSource = AllData;
comboBox2.DataSource = AllData;
comboBox1.ValueMember = "sehir";
comboBox2.ValueMember = "ilceler";
}
Very specific question, I know. I'm not sure how best to word this. Currently, my cell_formatting method will change the color of a cell based on its value:
dataGridView.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.cell_formatting);
....
public void cell_formatting(object sender, System.Windows.Forms.DataGridViewCellFormattingEventArgs e)
{
if (dataGridView.Columns[e.ColumnIndex].Name.Equals("LocCode"))
{
if (e.Value.ToString() == "OK")
{
e.CellStyle.BackColor = Color.Red;
}
}
}
What I actually need to do is check a different column index than that of the one I'm changing the color of. There's a column color that will decide what color the LocCode cell will change to.
I imagine there's a way to catch which item in my dataGridView.DataSource is being looked at while inside cell_formatting(), but I don't know how to access it.
I suggest you to use DataTable to get the color value. Here is an simple example for you.
I made a Table and add 3 records in it.
In form_load, data loaded to DataGridView,
DataTable dt;
private void Form1_Load(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection("Server=serverName;Database=db;Trusted_Connection=True");
conn.Open();
SqlCommand cmd = new SqlCommand("select * from TestTable", conn);
dt = new DataTable();
SqlDataAdapter adp = new SqlDataAdapter(cmd);
adp.Fill(dt);
dataGridView1.DataSource = dt;
}
Then, here we came cell_formatting event,
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name.Equals("TestName")) // LocCode
{
if (e.Value != null && e.Value.ToString() != "") // Check for extra line
{
string a = dt.Rows[e.RowIndex]["Color"].ToString(); //current row's Color column value.
e.CellStyle.BackColor = Color.FromName(a); // color as backcolor
}
}
}
Output;
Hope helps,
I imagine there's a way to catch which item in my dataGridView.DataSource is being looked at while inside cell_formatting(), but I don't know how to access it.
Sure there is.
First, use the DataGridViewCellFormattingEventArgs.RowIndex property to get the index of the row being formatted. Then use the index to the get the corresponding DataRow object, and finally use the DataGridViewRow.DataBoundItem property to get the corresponding data source object, casting it to the appropriate type:
var item = dataGridView.Rows[e.RowIndex].DataBoundItem as YourDataSourceObjectType;
I'm new in this and I'm a little lost.
Trying to show the values of my database in textbox by selecting in the combobox. But I can't.
Please help me. This is my code:
private void CargarDatos()
{
string consulta = "SELECT * FROM [dbo].[alumno]";
DataTable dt = new DataTable();
SqlConnection con = new SqlConnection(Properties.Settings.Default.conexion);
SqlCommand cmd = new SqlCommand(consulta, con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
try
{
con.Open();
da.Fill(dt);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
con.Close();
this.dataGridView1.DataSource = dt;
cbalumno.DataSource = dt;
cbalumno.DisplayMember="Nombre";
cbalumno.ValueMember="Id";
}
private void Form1_Load(object sender, EventArgs e)
{
CargarDatos();
}
private void cbalumno_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}
The parameters that i want to show are "Name" "Surname" and "DNI" of the table alumno.
Any ideas to how can I do that??
You can use DataRowView to get the record being bound with current SelectedItem. The Row property of DataRowView object will give you data row. Using this row you can get the columns being bound to it.
private void cbalumno_SelectedIndexChanged(object sender, EventArgs e)
{
DataRowView vrow = (DataRowView)cbalumno.SelectedItem;
string sValue = vrow.Row["Name"].ToString();
}
You already have placed the event cbalumno_SelectedIndexChanged in your code and now you have to use it.
Inside that event, just use the Text peroperty of that textbox and assign the value of the selected item in your combo box like this :
private void cbalumno_SelectedIndexChanged(object sender, EventArgs e)
{
yourTextBoxID.Text = comboBoxID.Text;
}
Hope this helps.
I have 4 textboxes in a windows form application and a gridview and button called 'Add'. All I want is, the data entered in 4 textboxes should be gone to the datagridview's four different columns in the same row as i click Add button. If i clear the text boxes, fill them again and click the Add button again then the data should go to the 2nd row of the gridview.
create a class like the following somewhere in your app
public class MyClass
{
public string field1 { get; set; }
public string field2 { get; set; }
public string field3 { get; set; }
public string field4 { get; set; }
}
inside your form.cs write this,
public static List<MyClass> lst = new List<MyClass>();
in the click event of your add button do this
private void btnAdd_Click(object sender, EventArgs e)
{
MyClass obj = new MyClass();
obj.field1 = txt1.Text.Trim();
obj.field2 = txt2.Text.Trim();
obj.field3 = txt3.Text.Trim();
obj.field4 = txt4.Text.Trim();
lst.Add(obj);
dataGridView1.DataSource = lst;
}
use this code:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
DataSet ds = new DataSet();
SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=Dataset;Integrated Security=True");
SqlDataAdapter ds1 = new SqlDataAdapter();
BindingSource bd = new BindingSource();
public Form1()
{
InitializeComponent();
}
private void btnAdd_Click(object sender, EventArgs e)
{
ds1.InsertCommand = new SqlCommand("INSERT INTO Employee VALUES(#FirstName,#LastName)", con);
ds1.InsertCommand.Parameters.Add("#FirstName", SqlDbType.VarChar).Value = txtFirstName.Text;
ds1.InsertCommand.Parameters.Add("#LastName", SqlDbType.VarChar).Value = txtLastName.Text;
con.Open();
ds1.InsertCommand.ExecuteNonQuery();
con.Close();
}
private void btndisplay_Click(object sender, EventArgs e)
{
ds1.SelectCommand = new SqlCommand("Select * from Employee", con);
ds.Clear();
ds1.Fill(ds);
dataGridView1.DataSource = ds.Tables[0];
bd.DataSource = ds.Tables[0];
//txtFirstName.DataBindings.Add("Text", bd, "FirstName");
//txtLastName.DataBindings.Add("Text", bd, "LastName");
}
private void btnPervious_Click(object sender, EventArgs e)
{
bd.MovePrevious();
update();
records();
}
private void btnNext_Click(object sender, EventArgs e)
{
bd.MoveNext();
update();
records();
}
private void btnFirst_Click(object sender, EventArgs e)
{
bd.MoveFirst();
update();
records();
}
private void btnLast_Click(object sender, EventArgs e)
{
bd.MoveLast();
update();
records();
}
private void update()
{
dataGridView1.ClearSelection();
dataGridView1.Rows[bd.Position].Selected = true;
records();
}
private void records()
{
label1.Text = "records" + bd.Position + " of " + (bd.Count - 1);
}
dont forget to markup this answer
Steps to follow:
1) Upon Binding the DataGrid View, save the DataSource in a Viewstate Variable
2) Define Click event for Add Button
In the click event, recall the Viewstate Variable that has the datasource, Cast it as a DataTable. Make a new row of that datatable, assign values to the cells of the new row. Add this new row to the Datatable, Save the dataTable in ViewSate again, Bind the datasource to the DataGrid
That's All~
Thanks to Mr. SHAKIR SHABBIR first of all, but as i think there is no viewstate in windows form application...
i suggest to use static collection types...
you can define a class for your entry form and foreach textbox a variable, when you click the add button create object of the class, setting all its values with your textboxes, inserting row in grid, and saving all rows data(object of class per gridview row) in a List
you can also use a static datatable... you have to create columns for each of your textfield..
adding row to datatable.. selecting the datasource of your grid...
if you need further help, i am alway here to help you..
I am getting a datagridview default error dialog box. There it said handle the dataerror event.
I am loading the data in myy DGV from a datatable. When I try to add a new row, I click on the empty row with a (*). When I start typing some values in the new row cell, then the dataerror is shown and goes in a infinte loop.
DataGridViewDataError.context = display.
Error: Index 3 does not have a value.
My grid has 3rows and here the new row will have index 3.
Here's the code where the DGV is loaded
private void frmPlant_Load(object sender, EventArgs e)
{
Program.fMain = this;
Program.LoadAllForms();
string selectCommand = "select * from T1";
FillData(selectCommand);
}
private void FillData(string selectCommand)
{
using (SQLiteConnection conn = new SQLiteConnection(connString))
{
conn.Open();
dataGridView1.AutoGenerateColumns = true;
da = new SQLiteDataAdapter("selectCommand", connString);
ds = new DataSet();
commandBuilder = new SQLiteCommandBuilder(da);
da.Fill(ds, "T1");
dt = ds.Tables[0];
dataGridView1.DataSource = ds.Tables[0];
dataGridView1.DataMember = "T1";
dataGridView1.Columns["TID"].ReadOnly = true;
}
}
I don't know where exactly in the code this is happening. Handled the DataError event. Not sure if UserAddedRows, RowsValidating would be useful
private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
MessageBox.Show(e.Context.ToString());
e.Cancel = true;
}
Thank you
Sun
MSDN sais the following:
The ColumnIndex and RowIndex properties of the DataGridViewDataErrorEventArgs object associated with this event normally indicate the cell in which the data error occurred. When the error occurs in an external data source, however, the data source may not provide the column in which the error occurred. In this case, the ColumnIndex property typically indicates the column of the current cell at the time of the error.
Use those properties to find out in which column does the error occur.
Not sure. Try to replace MessageBox.Show statements with System.Diagnostics.Debug.WriteLine and do the same in RowsValidating event. MessageBox could cause the problems in this case because it "pauses" the processing.
private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.Context.ToString());
e.Cancel = true;
}