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;
}
Related
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.
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 want first row cell of DGV to be not selected, Whenever my application initializes. I'm using the following code, but it only works when I disable Timer (I really don't know the reason).
private void BindData()
{
try
{
DataTable dt = DeviceData.BindData(BMS_Controls.ClsConstant.DEVICETYPE.PRIMARY_PUMPS.ToString());
bindingSource1.DataSource = dt;
dataGridView1.DataSource = bindingSource1;
dataGridView1.ClearSelection();
dataGridView1.Refresh();
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
private void frmPrimaryPumps_Load(object sender, EventArgs e)
{
BindData();
timer1.Interval = 1000;
timer1.Start();
}
I'm using Timer to call BindData method after the wait of 1 second.
Could anyone please tell me how can I disable first row selection, and call the BindData method successfully using Timer?
You should try setting the datagridview1.CurrentCell = null after assigning the DataSource, this should remove the selection of the first row/cell from your grid.
call
dgv.ClearSelection();
on DataBindingsCompleted event
like following
dgv.DataBindingComplete += new DataGridViewBindingCompleteEventHandler(dgv_DataBindingComplete);
private void dgv_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
DataGridView d = sender as DataGridView;
d.ClearSelection();
}
It worked for me with adding the line you already added:
dataGridView1.ClearSelection();
try removing refresh method.
I am new at this. I am trying to populate a datagrid from a table source. My code is attempting to do two things.
First it populates a dataGrid with columns from a table. Then it adds a column called "SELECT" at the end of the grid. This select is CheckBox. However, when I execute this code, it adds the "SELECT" column twice.
I want to see it once. What am I doing wrong?
private void BankFlow_Load(object sender, EventArgs e)
{
initMethod();
dataTable = getBankFlowData(globalConnection);
dataGridView1.DataSource = dataTable;
}
private static DataTable getBankFlowData(OracleConnection oc)
{
DataTable dt = new System.Data.DataTable();
try
{
OracleCommand od = oc.CreateCommand();
od.CommandText = "SELECT * FROM BANK_FLOW_SOURCE";
od.CommandType = System.Data.CommandType.Text;
OracleDataAdapter adapter = new OracleDataAdapter(od);
adapter.Fill(dt);
}
catch (Exception)
{
}
return dt;
}
private static void initMethod()
{
targetSystem = ConfigurationManager.ConnectionStrings["prototype"].ConnectionString.ToString();
Console.WriteLine("Target : {0}", targetSystem);
sourceSystem = ConfigurationManager.ConnectionStrings["qlprod8"].ConnectionString.ToString();
Console.WriteLine("Source : {0}", sourceSystem);
globalConnection.ConnectionString = sourceSystem;
globalConnection.Open();
}
private void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
DataGridViewCheckBoxColumn col = new DataGridViewCheckBoxColumn();
col.HeaderText = "SELECT";
col.ReadOnly = false;
col.DefaultCellStyle.BackColor = Color.Beige;
dataGridView1.Columns.Add(col);
}
Your problem is that the databindingcomplete event happens more then you think. In fact anytime some data changes it will fire.
You need to add the column outside of the databindingcomplete event.
EDIT
Actually since you are databinding, you may want to consider adding the column to your datatable. You would do this before the binding the datatable to the grid. Essentially, just create a datacolumn named select, that has the type of boolean and then add the datacolumn to the datatable.