I can save data in my gridView but I am unable to do so to my datasource.
Could there a missing line of code or is there something that I am missing?
Here's my code:
public Marksheet(object val1)
{
InitializeComponent();
string connectionString = null;
SqlConnection conn;
connectionString = "Server=localhost\\SQLEXPRESS;Integrated security=SSPI;database=jms";
SqlDataAdapter sda6 = new SqlDataAdapter("SELECT * FROM grades WHERE class_code='" + val1 + "'", connectionString);
conn = new SqlConnection(connectionString);
DataTable dt5 = new System.Data.DataTable();
sda6.Fill(dt5);
gridControl1.DataSource = dt5;
}
private void gridControl1_EmbeddedNavigator_ButtonClick(object sender, NavigatorButtonClickEventArgs e)
{
if (e.Button.ButtonType == DevExpress.XtraEditors.NavigatorButtonType.EndEdit)
{
if (MessageBox.Show("Do you want to commit changes to the current record?", "Confirm commit",
MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) != DialogResult.No)
{
gridView1.CloseEditor();
gridView1.UpdateCurrentRow();
}
}
}
private void gridView1_CellValueChanged(object sender, CellValueChangedEventArgs e)
{
//?? Could there be something I'm missing here? if yes, what could it be?
}
When you make any changes to the grid control, the changes are reflected in the datasource, that is in your case a DataTable. If you think logically, it seems correct as the Grid Control is bound to the DataTable and is not aware about how the DataTable gets populated.
Now you can see that the DataTable is populated using DataAdapter. You need to call the DataAdapter.Update(dataTable) method to push the changes to database.
As described here - Posting Data to a Connected Database
The best approach is already suggested by #Aseem that you need to implement ADO.net binding to commit changes back to the back-end using the DataAdapter. If you can implement this way then check below tutorial:
Tutorial: ADO.NET Data
When binding to a database using ADO.NET, you bind a control to a
DataTable containing data from the database. When you change data via
the Grid Control (adding, deleting or modifying records), the changes
are accumulated in the DataTable. They are not automatically posted to
the underlying database. Therefore, you need to manually call a
specific method to post the changes.
If you are using custom data table and not willing to implement such binging then you have to handle GridView.RowUpdated Event and then you can post back then changes that you made in current updated row.
Refer this: Xtragrid Row Updated Event
Example:
Private Sub gridView1_RowUpdated(ByVal sender As System.Object, ByVal e As DevExpress.XtraGrid.Views.Base.RowObjectEventArgs) Handles gridView1.RowUpdated
Dim val As Object
Dim row As DataRowView = CType(e.Row, DataRowView)
val = row(0)
End Sub
Hope this help..
Related
So I'm trying to cope with an app project in c#/mssql.
It is Windows Froms app.
I'm connected to db, I can show all the tables in my db in the form onload, but i don't know how, or if I can do sth like: when these table names shows click on any and it will send the db name as a variable to function, which will show me the content of the folowing table. I've learned about cellclick event, but i still don't know how do i make it work.
So the code below works perfectly fine
DbClassShow showObj = new DbClassShow();
private void MyWindow_Load(object sender, EventArgs e)
{
DataTable dt = showObj.Select();
QueryView.DataSource = dt;
}
but I want it to show the content of the table, when i click on it, but I can't attach like clik event to table name, because when the app is not running i can't even see content of the data grid view.
What do I do in this situation?
Sorry guys for bothering, I've been trying this and had no clue, but finally I resolved it on my own! Here's what i did:
dbClassTables showTab = new dbClassTables();
private void QueryView_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
{
int indexOfRow = e.RowIndex;
DataGridViewRow selectedRow = QueryView.Rows[indexOfRow];
DataTable dt1 = showTab.Select(selectedRow.Cells[2].Value.ToString());
QueryView.DataSource = dt1;
}
Created a new class with select method with parameter and it works, I'm gonna make it more valid using abstract class or interface i think, but yeah, that's it.
public DataTable Select(string tbl_name)
{
...
string sql = "SELECT * FROM {0}";
string data = tbl_name;
sql= string.Format(sql, data);
So I finally got my code somewhat working. So where it will delete from the Datagrid. But, It does not delete from the database at all.
I am using Data sources to do it.
Here is my button command.
private void delete_Click(object sender, RoutedEventArgs e)
{
DataGrid dg = this.nAMEDataGrid;
if (dg != null)
{
var toDelete = (IList)dg.SelectedItems;
var collection = toDelete.Cast<DataRowView>();
var list = new List<DataRowView>(collection);
foreach (var item in list)
{
item.Row.Delete();
}
}
}
I just need it to delete from the database as well. But, I do not know why it isnt...
what about getting the id of your selected item from the grid and pass it as parameter to your database delete command then rebind your data grid?
You still need to perform the operation against a database connection (which is usually best tied to the DeleteCommand event from the datagrid). The way to perform the database deletion depends on your data access strategy - if you are using Entity Framework, some other ORM, or directly tied to the SqlCommand and SqlConnection if using SQL Server.
Here's a full walkthrough:
http://www.c-sharpcorner.com/uploadfile/17e8f6/insert-update-and-delete-in-datagrid-in-Asp-Net/
When user select any record from the GridView then my DetailView is updated based on the selection of the GridView. So what I am trying to do is that when I delete anything from the DetailView then I want to refresh the GridView so basically I don’t want to show still the deleted record in the GridView. I have tried to resolve this issue by doing the data bind after my connection and SQL statement but it does not refresh it. One thing to note is that I am using a Accordion pane but both my gridview and the detailview are on the same pane. I am not sure if this is breaking anything. Here is my code:
protected void Refresh_ItemCommand(object sender, DetailsViewCommandEventArgs e)
{
if (e.CommandName.Equals("Delete", StringComparison.CurrentCultureIgnoreCase))
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
SqlDataAdapter da = new SqlDataAdapter("select ID, Name, Address from dbo.MyTable", con);
DataTable dt = new DataTable();
da.Fill(dt);
Gridview1.DataSource = dt;
Gridview1.DataBind();
}
}
You may use the event of the Data view called "ItemDeleted" as follows:
DetailViewName_ItemDeleted(object sender,
DetailsViewDeletedEventArgs e)
{
// Refresh the GridView control after a new record is updated
// in the DetailsView control.
GridViewName.DataBind();
}
The above code is from the official MSDN site for detail view control.
The other way (which I prefer) is to handle the data grid during the Page_load procedure so when you press your delete button in the detail view, the page will perform a postback.
So in the procedure Page_load you can call another procedure which fills the data grid. The code might be like this:
if (isPostback)
{
FillGrid();
}
private void FillGrid()
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
SqlDataAdapter da = new SqlDataAdapter("select ID, Name, Address from dbo.MyTable", con);
DataTable dt = new DataTable();
da.Fill(dt);
Gridview1.DataSource = dt;
Gridview1.DataBind();
}
Your code doesn't show anything where the record is actually deleted so it's understandable that when you re-fetch the data still contains everything.
What you need to do is:
Execute a sql statement to delete the record
Re-fetch the data
Rebind the data.
If you follow those 3 steps it will work.
try to use the event that is called in case of pressing the delete key from the DGV
private void DGV_DeleteKeyPressed(object sender, KeyEventArgs e)
{
//enter code here
}
I have added a record to the underlying db and after I add the record i do a
datagridview.Refresh(); and i dont see the newly added record.
If i stop and start the application its there. What am I doing or not
doing?
Notes : button1 and datagridview is in different Forms.I made datagridview's Modifiers public. This project is ado.net project
public class CustomerService
{
public List<Customers> ShowAll()
{
List<Customers> customers = new List<Customers>();
SqlConnection conn = new SqlConnection("data source=.; database=custer; user id=sa; password=*****");
SqlCommand cmd = new SqlCommand(" select * from Customers ", conn.Open());
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
Customer customer = new Customer ()
{
CustomerID = dr.GetInt32(0),
CustomerName = dr.GetString(1),
CustomerSurname = dr.GetString(2),
};
customers.Add(customer);
}
conn.Close();
return customers;
}
}
private void button1_Click(object sender, EventArgs e)
{
CustomerService service = new CustomerService();
if (txtCustomerName.Text != "" || txtCustomerSurname.Text != "")
{
customerservice.customerAdd(txtCustomerName.Text, txtCustomerSurname.Text);//this rows is other method .I am using for adding new customer
MessageBox.Show("Customer Added");
Form1.dataGridView1.DataSource = service.ShowAll();
Form1.dataGridView1.Refresh();
}
else
{
//……………
}
}
After adding the data to the DB, your application knows nothing about the data added. You need to load those data to memory. Retrieve all the data you want to display from the database and bind it explicitly to UI after doing operations on database.
EDIT:
Can you check what ShowAll() returns while debugging? Does it return you the data you actually want?
If it is a WPF application take a look here. The issue here is to tell your UI component that underlying data source has been changed, so the UI component reflects the changes made to data.
Again if it is a WPF application, you can define your data as ObservableCollection and bind you UI to this collection. ObservableCollection automatically requests UI to refresh when data has changed.
Rica ederim .)
The usual way of doing this is to reset the DataSource of the DataGridView.
Try like this code (with correct code to provide the right datasource):
Form1.dataGridView1.DataSource = typeof(List);
Form1.dataGridView1.DataSource = service.ShowAll();
Calling .Refresh() doesn't work since it only forces a repaint, but the code that paints the grid doesn't know of the changes.
Ref this WPF link also, that may help you:
Why does the DataGrid not update when the ItemsSource is changed?
Try calling EndEdit on the datagridview:
this.dataGridView1.EndEdit();
Second, refresh the grid view:
this.dataGridView1.Refresh();
And if that still doesn't work, try calling Refresh on the containing control
ParentControl.Refresh()
This will end up calling a repaint that might be needed.
what is the content of customerservice.customerAdd ?
Maybe it doesnt close the connection properly/doesnt flush the data into the db,and it only happens when you close your app(all memory is disposed,and all connections are closed/flushed).
Also - I suggest using a BindingSource that the grid is bound to,and changing its data source - it has event to notify the grid automaticallly if its data source has changed and that will cause it to refresh.
As you said these are in different forms, I think the pointer to Form1 doesn't point to the form that you want. you should pass the pointer of that form with this to this form.
When you are creating form 2 define like this:
Form2 = new Form2();
Form2.form1 = this;
Then your code should work.
It appears you're using a List as the datasource. I've found using a generic list is ok for read only data but for doing any kind of updates you need something with more power. I don't know about WPF but in winForms I've had great success with the IBindingList interface and the BindingList generic collection. The BindingList generic collection implements the IBindingList interface for you. I would read the MSDN articles on both of them. I've pretty much stopped using the IBindingList interface but it's still perfectly fine to implement.
http://msdn.microsoft.com/en-us/library/system.componentmodel.ibindinglist.aspx
http://msdn.microsoft.com/en-us/library/ms132679.aspx
The answer is to have the gridview connected to the BindingList<Customers> rather than the List<Customers> . Hope this will solve your problem...
If you change the List to a BindingList you'll have success. I threw together a sample which just had a DataGridView and a couple of Buttons on a Form.
button1 generates some fake data and assigns the datasource.
button2 adds another Customer to the underlying list.
The DataGridView is updated when the underlying BindingList changes.
Code:
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string SurName { get; set; }
}
public partial class Form1 : Form
{
BindingList<Customer> customers = new BindingList<Customer>();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; ++i)
{
customers.Add(new Customer
{
Id = i,
Name = "Name" + i,
SurName = "Surname" + i
});
}
dataGridView1.DataSource = customers;
}
private void button2_Click(object sender, EventArgs e)
{
customers.Add(new Customer
{
Id = 22,
Name = "Newname",
SurName = "Newsurname"
});
}
}
Now, the reason this works is that BindingList<T> implements IBindingList, among other things, and that interface has, among other things, an event called ListChanged which is raised when the list or something in the list changes.
If you are not bound to use customer list strictly as data-source for datagridview then
Here is much better solution using datatable. You will get updated customer list and datagridview after insert
public class CustomerService
{
public DataTable ShowCustomers()
{
string cns = "data source=.; database=custer; user id=sa; password=*****";
SqlConnection conn = new SqlConnection(cns);
SqlDataAdapter da = new SqDataAdapter("select * from Customers", conn);
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
}
private void button1_Click(object sender, EventArgs e)
{
CustomerService service = new CustomerService();
if (txtCustomerName.Text != "" || txtCustomerSurname.Text != "")
{
customerservice.customerAdd(txtCustomerName.Text,txtCustomerSurname.Text);
MessageBox.Show("Customer Added");
DataTable dt = service.ShowCustomers();
Form1.dataGridView1.DataSource = dt;
//If you also need customer list. Provide the DataTable and get list
List<Customers> customers = new List<Customers>();
for (int i=0;i<dt.Rows.Count;i++)
{
Customer customer = new Customer();
customer.CustomerID = Convert.ToInt32(dt.Rows[i][0]);
customer.CustomerName = dt.Rows[i][1].ToString();
customer.CustomerSurname = dt.Rows[i][2].ToString();
customers.Add(customer);
}
}
}
You need to do data binding only once not on every new record. That's the whole point of binding data to a control that all changes will be auto reflected.
Make customers a data member of the CustomerService class and change your code appropriately:
class CustomerService {
List<Customers> customers;
...
}
Next the binding code should be done once, maybe when the first record is added to the List<Customers>.
BindingSource binding = new BindingSource();
binding.DataSource = customers;
dataGridView1.DataSource = binding;
If you have done this right, every time any record is deleted or added to the customers collection, it should be automatically be reflected in the DataGridView control.
I think you must have used update panel and might not refreshing that
I think this will solve your problem, Check this........
DataGrid.CommitEdit();
DataGrid.Items.Refresh();
NOTE
CommitEdit() method will fire the RowEditEnding event, it is a endless loop. WPF does not allow to refresh the view while it is editing, since it may occur the endless loop. However, you could refresh the view after editing. Try to remove the RowEditEnding event handler (If Initialzed) , and do refresh for the Items; Then add the event handler back:
I have a datagridview with a filter for doing search. If I update the database and then reset the dgv to the datasource I lose my filter. I tried doing ResetBindings but that didn't help. If I close the form and reopen the changes are there, I'd just like it to happen in "real time". Any advice is appreciated.
I have a dataset based on a SQL view. In this dataset there is a table based on this view. The datagridview is bound to this table. I have several controls including textboxes and combo boxes which are bound to columns in the dgv. I have a textbox which is used to search on the grid:
private void txtFilterString_TextChanged(object sender, EventArgs e)
{
ToolStripTextBox tb = (ToolStripTextBox)sender;
DataView dv = tILEDataSet.vwTILEAdmin.DefaultView;
vwTILEAdminBindingSource.Filter =
string.Format(#"PdcProductName LIKE '%{0}%' OR LabelDescription LIKE '%{0}%' OR LabelProductName LIKE '%{0}%'",
tb.Text.Trim().Replace("'", "''"));
dataGridView1.Refresh();
}
After making changes to a row in the dgv by modifying one or more of the bound controls I save the changes, which update the table:
sql.Append(#"UPDATE [dbo].[LabeledProducts]
SET [PdcProductName] = #pdcProd
,[LabelProductName] = #lblProd
,[LabelDescription] = #lblDesc
,[Power] = #pwr
,[Fabrication] = 0
,[UL_File_Number] = ''
,[PrePrintedSerial] = 0
,[ShowOrderOnLabel] = 0
,[PrivateLabelLogoId] = #plid
,[AgencyImageId] = #aid
,[WireDiagConfigId] = #wid
WHERE PdcProductName = '").Append(pdcProductName).Append("'");
using (SqlCommand command = new SqlCommand(sql.ToString(), printConfigTableAdapter.Connection))
{
if (vwTILEAdminTableAdapter.Connection.State != ConnectionState.Open)
vwTILEAdminTableAdapter.Connection.Open();
LabeledProductsDataTableAdapter.UpdateCommand = command;
LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("#pdcProd", txtPdcProdName.Text);
LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("#lblProd", txtLabeledProd.Text);
LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("#lblDesc", txtLabelDesc.Text);
LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("#pwr", txtPower.Text);
// we need ulfilename and mod
LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("#plid", LogoId);
LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("#aid", AgencyId);
LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("#wid", WireId);
DataTable dt = new DataTable();
int rowsAffected = LabeledProductsDataTableAdapter.Update(dt);
rowsAffected = command.ExecuteNonQuery();
dataGridView1.Refresh();
//dataGridView1.DataSource = tILEDataSet.vwTILEAdmin;
//this.vwTILEAdminBindingSource.ResetBindings(true);
}
If I uncomment the line where I set the DataSource, I get a refreshed view, but the textbox used to generate the filter on the binding source no longer works, e.g. regardless of what I type in the textbox. The Text_Changed event does still get called, but the filter no longer has any affect on the contents of the dgv.
It looks like your problem is something very simple.
In these lines:
dataGridView1.DataSource = tILEDataSet.vwTILEAdmin;
this.vwTILEAdminBindingSource.ResetBindings(true);
You set the data source of the grid to be vwTILEAdmin, but in your filter code you are filtering on the binding source which is no longer the data source of the grid!
Try instead:
this.vwTILEAdminBindingSource.DataSource = tILEDataSet.vwTILEAdmin;
this.vwTILEAdminBindingSource.ResetBindings(true);
Also you probably don't need the .Refresh() calls on the grid - the method doesn't actually refresh a grid's data source. It only redraws the grid client area, and if you have a stale data source (where the grid doesn't know data has changed) the redraw won't make a difference.
If you are still having problems it could be that the update to the grids data source is not propogating - that is not raising the ListChanged event which the grid listens to to know when to update. If that is the case then you need to null the data source and reset it.
dataGridView1.DataSource = typeof(List<string>);
dataGridView1.DataSource = newDataSource;
In the code above the data source is set to typeof(List) since this keeps any existing columns. You would then set your binding source to the grid datasource again. Though I doubt this will be necessary - the binding source ResetBindings call should be enough.