My project is c# windows form with Entity Framework , and I have DataGridView with a TextColumn. I want to edit the last column TextColumn Cells[3].
To get all values from database to GridView is not problem. I get them.
And I can put a new value but as soon as I click ontherplace then it changes to the old value. Textbox is not keeping the new value that I want to edit.
ReadOnly is false for this cells in column 3 becouse I can write but changes back the new value to the old values.
What kind of events I'am missing and how shall I do to fix this problem? By some how it seems like the hole Gridview is locked. Please Help.
I tried even:
foreach (DataGridViewRow row in dgvOrder.Rows)
{
row.Cells[3].ReadOnly = false;
}
Here below is my code.
private void Treatments_Load(object sender, EventArgs e)
{
try
{
using (MyHealthEntities db = new MyHealthEntities())
{
var orderd = db.Order.Where(x => x.Ordernr == OrNr).FirstOrDefault();
if(orderd != null)
{
var myOrder = (from u in db.....
join d in ...
join m in ...
where u.....
select new
{
OrderId = m.MedId,
Name = m. Name,
Quality = m.Quality,
Description = d.Description
}
).ToList();
if (myOrder != null)
{
dgvOrder.DataSource = myOrder ;
}
}
foreach (DataGridViewRow row in dgvOrder.Rows)
{
row.Cells[3].ReadOnly = false;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
If I'm not mistaken, a normal System.Collections.Generic.List will not support editing when directly bound to because it does not implement IBindingList (or the necessary ListChanged event) for two-way data binding. You will likely need to wrap the List into a BindingList in order to edit the values. This will not be possible with an anonymous type.
First, create a class to store your List items:
public Class Order {
public int OrderID { get; set; }
public string Name { get; set; }
public byte Quality { get; set; }
public string Description { get; set; }
}
Then in your query,
select new Order
{
OrderId = m.MedId,
Name = m. Name,
Quality = m.Quality,
Description = d.Description
}
Now move it to a BindingList:
if (myOrder != null) {
BindingList<Order> myBindingList = New BindingList<Order>(myOrder);
dgvOrder.DataSource = myBindingList;
}
I would also recommend wrapping the BindingList in a BindingSource, which will prevent you from having to handle rows being added/deleted manually:
if (myOrder != null) {
BindingList<Order> myBindingList = New BindingList<Order>(myOrder);
BindingSource myBindingSource = New BindingSource(myBindingList);
dgvOrder.DataSource = myBindingSource;
}
Apologies if my syntax is a little off, I've been mostly using vb as of late.
EDIT: I missed that BindingList does not implement IContainer, so the above code for binding to a BindingSource will not work because the single-parameter constructor for BindingSource specifically takes an IContainer. If you still want to use a BindingSource, the third constructor of BindingSource should be used instead, like so:
BindingSource myBindingSource = New BindingSource(myBindingList, Nothing);
BindingSource does accept binding to an IBindingList, but only using this constructor or by directly setting the .DataSource property after using the parameterless constructor.
Leaving the erroneous code above so others who read OP's comment will understand what was being referenced.
You can't edit DataGrid itens when you are using "dgvOrder.DataSource = myOrder".
My suggestion is you do and "for each" in your myOrder list and add row by Row into Grid. After, you can do an other "for each", recovery the datas from DataGrid and Save the itens in your db.Order.
Related
I have class
public class Students
{
public int StudentsID { get; set; }
public string name{ get; set; }
}
And I use a list of objects. Then I add the objects from the file and display this list in datagridview like that:
List<Students> listStudents = new List<Students>();
for (int i = 0; i < listStudents.Count; i++)
{
dataGridView2.Rows.Add(listStudents[i].name, listStudents[i].StudentsID);
}
And now is the question. How would I know which object is selected.
I tried this, but it does not work - currentObject is null
private void btn_Click(object sender, EventArgs e)
{
Students currentObject = (Students)dataGridView1.CurrentRow.DataBoundItem;
}
People who are new to using Winforms and DataGridViews, tend to add the rows of the DataGridView themselves.
But there is a much easier way: use the DataSource of the DataGridView.
You plan to show Students in your DataGridView. You'll probably have two columns, the one where you show the StudentsId, and the one where you show the Name.
Every DataGridViewColumn has a string property DataGridViewColumn.dataPropertyName This property contains the name of the property that this column should show.
So to show the Id and the name, you need something like:
columnStudentId.DataPropertyName = nameof(Student.StudentId);
columnStudentName.DataPropertyName = nameof(Student.Name);
You will probably set these properties using the visual studio designer.
Now to show the Students, one Student per row, all you have to do is assign the collection to the DataSource of the DataGridView:
List<Student> students = ...
this.DataGridView1.DataSource = students;
And bingo, the names and id of every Student is shown in the DataGridView.
The solution is a one-time only: changes are not recorded. If you want that changes in the table are updated automatically, put the items in a BindingList<Student>:
private BindlingList<Student> students;
private void DisplayStudents(IEnumerable<Student> students)
{
this.students = new BindingList<Student>(students.ToList());
this.dataGridView1.DataSource = this.students;
}
Any changes made by the operator are automatically updated in this.students, any change that you make to this.Students is automatically displayed.
private void AddOrUpdateStudent(Student studentToUpdate)
{
// Is there already a Student with this Id shown?
var existingStudent = this.Students
.Where(student => student.StudentId == studentToUpdate.StudentId)
.FirstOrDefault();
if (existingStudent != null)
{
// Student exists, update the name:
existingStudent.Name == studentToUpdate.Name;
}
else
{
// Student does not exist yet; add it:
this.Students.Add(studentToUpdate);
}
}
The datagrid view is automatically updated.
Similarly the other way round: operator edits one or more cells in the datagridview and presses a button:
private void OnButtonOk_Clicked(object sender, ...)
{
// all edited cells are already updated in this.Students:
this.ProcessStudents(this.Students);
}
To get the Student that is displayed in a certain row, you can use property DataGridViewRow.DataBoundItem
IEnumerable<Student> selectedStudents = this.dataGridView1.SelectedRows
.Cast<DataGridViewRow>()
.Select(row => (Student)row.DataBoundItem);
remove this code:
for (int i = 0; i < listStudents.Count; i++)
{
dataGridView2.Rows.Add(listStudents[i].name, listStudents[i].StudentsID);
}
add your list to Datagridview datasource :
dataGridView2.DataSource = listStudents;
to get the current row as object :
Students currentObject = (Students)dataGridView2.CurrentRow.DataBoundItem;
Just do this:
List<Students> listStudents = new List<Students>();
...
dataGridView2.DataSource = listStudents;
And get rid of the "for" loop.
I'm using datagrid as the temporary list that until I decide to insert in the database all the data remain in datagrid. I'm adding functions like adding new records, deleting or editing. but I can not change selectedrow
my code is
gridlist.Items.Add(new { num_ins = num_ins.Text, dat_ins = DateTime.Now.ToShortDateString()} --> and many other value
and for delete
var selectedItem = gridlist.SelectedItem;
if (selectedItem != null)
{
gridlist.Items.Remove(selectedItem);
}
i want to make something like this
gridlist.Columns[0].gridlist.Items[1]= "my value";
I wanted to know if it is possible to do this directly from the datagrid as a removal or creation of new records
There are two possibilities.
If you always just add an anonymous type to the Items collection, then it is not possible no update the individual column values. You can however, update the entire row
gridlist.Items[0] = new { num_ins = 1, dat_ins = DateTime.Now};
If you could create a class/structure with public properties for the items being added, then you can update the individual properties of the items.
public class temp
{
public int num_ins {get;set;}
public DateTime dat_ins {get;set;}
}
((gridlist.Items[0] as temp)).num_ins = 3;
i'm newbie in devexpress. when i add new row and fill some value to one cell, then i focus to other cell in same row i lost value in that cell.
This is my code (column name in gridview match with coumn in Datatable dtGroupRole)
FrmUser.cs
...
adminGroupRoles = AdminGroupRoles.GetAllGroupRoles().ToList();
dtGroupRole = GlobalVars.ToDataTable<AdminGroupRoles>(adminGroupRoles);
grdGroupRoles.DataSource = adminGroupRoles;
AdminGroupRoles.cs
public class AdminGroupRoles
{
public int GroupId { get; set; }
public string GroupName { get; set; }
public static List<AdminGroupRoles> GetAllGroupRoles()
{
return AdminGroupRoles.Inst.ExeStoreToList("sp_AdminUsers_GetAllGroupRoles");
}
}
The edited cell was reset:
Thanks all :)
I see that you assign adminGroupRoles as the grid source. It's a List. So that the grid can add new rows, the data source should be IBindingList. adminGroupRoles doesn't implement it. As far as I understand, dtGroupRole is DataTable converted from adminGroupRoles. So, you need to use as the grid data source:
adminGroupRoles = AdminGroupRoles.GetAllGroupRoles().ToList();
dtGroupRole = GlobalVars.ToDataTable<AdminGroupRoles>(adminGroupRoles);
grdGroupRoles.DataSource = dtGroupRole;
Use BindingList instead of List as Gosha_Fighten replied. Then you can convert your bindinglist to list like:
List <T> list = yourbindinglist.Select(b => b).ToList();
OR convert your list<T> to bindinglist<T> like:
yourBindingList = new BindingList<T>(listToConvert);
How can I call my function in this data gridview? I would like to make the sum of these two to be displayed in the highlighted datagridview:
foreach (DataRow row in dt.Rows) {
datagridview_information.Rows.Add();
datagridview_information.Rows[counterSelected].Cells[0].Value = row["BrandName"].ToString();
datagridview_information.Rows[counterSelected].Cells[1].Value = row["GenericName"].ToString();
datagridview_information.Rows[counterSelected].Cells[2].Value = row["PresDayOfIntake"].ToString();
datagridview_information.Rows[counterSelected].Cells[3].Value = row["Status"].ToString();
datagridview_information.Rows[counterSelected].Cells[4].Value = "5";
datagridview_information.Rows[counterSelected].Cells[5].Value = medicineLeft();
datagridview_information.Rows[counterSelected].Cells[7].Value = row["ContainerNumber"].ToString();
datagridview_information.Rows[counterSelected].Cells[8].Value = row["Status"].ToString(); ;
counterSelected++;
}
}
}
public int medicineLeft()
{
for (int i = 0; i < datagridview_schedule.Rows.Count; ++i)
{
medleft += Convert.ToInt32(datagridview_information.Rows[i].Cells[8]) - Convert.ToInt32(datagridview_medicine.Rows[i].Cells[4]);
datagridview_information.Rows[i].Cells[5].Value = Convert.ToString(medleft);
}
return medicineLeft();
}
You're going to have to give more code here, I have absolutely no idea what you're trying to do. Is medleft declared elsewhere?
Your medicineLeft() method is returning itself, meaning it'll run as an infinite loop and will probably throw a StackOverflow exception on this line:
datagridview_information.Rows[counterSelected].Cells[5].Value = medicineLeft();
Your medicineLeft method needs to return an integer - is it meant to return medleft? If so, changing it to return medleft; should fix this.
One easy solution would be to change the way you populate the DataGridView. If I were doing this, I would do the following:
Create a class object to store the data you want in your grid:
public class Medicine
{
public string BrandName { get; set; }
public string GenericName { get; set; }
<... add other properties ...>
}
Instantiate a collection of Medicine objects that you want to bind to the DataGridView.
public List<Medicine> GetMedicine(DataRowCollection rows)
{
List<Medicine> medicines = new List<Medicine>();
foreach (DataRow row in rows)
{
Medicine medicine = new Medicine();
medicine.BrandName = row["BrandName"] == null ? string.Empty : row["BrandName"].ToString();
medicine.GenericName = row["GenericName"] == null ? string.Empty : row["GenericName"].ToString();
//more rows here to populate Medicine object
//include the call to whatever methods are needed to populate the object
medicines.Add(medicine);
}
return medicines;
}
Bind the collection to the DataGridView
datagridview_information.DataSource = GetMedicines(dt.Rows);
I find it easy to create the DataGridView control on the form, set the columns in the designer, and set the AutoGenerateColumns property to false in code so that the grid appears as I wish. It is up to you how you want to handle that.
I am trying to get the Row's particular column from selected item in wpf from DataGrid.
Name of DataGrid is Datagrid_Newsale.
I am getting alert of whole row when it is selected, So i tried mapping its column.
Say if row is-
{ ID = 3, CustomerName = xyz, SaleDate = 05.08.2013 00:00:00, TotalAmount = 10 }
Then it's column CustomerName=xyz is to be shown in textbox.
Getting row-
var copyitem = Datagrid_NewSale.SelectedItem;
if (copyitem == null)
{
MessageBox.Show("Please select values from list");
}
if (copyitem != null)
{
MessageBox.Show(copyitem.ToString());
}
For getting customerName into text box i tried creating a new instance of model-
public class CustomerDetailes
{
public string CustomerName { get; set; }
}
And values from database from Customer Table-
public void viewcustomername()
{
List<CustomerDetailes> ilist = null;
ilist = (from order in db.Customer
select new CustomerDetailes
{
CustomerName= order.CustomerName
}).ToList();
txtCustumer.Text = ilist.ToString();
}
So giving it one more try-
CustomerDetailes copyitem = (CustomerDetailes)Datagrid_NewSale.SelectedItem;
if (copyitem == null)
{
MessageBox.Show("Please select values from list");
}
if (copyitem != null)
{
MessageBox.Show(copyitem.ToString());
}
txtCustomer.text=copyitem.CustomerName; //CustomerName into a textbox
But it is referencing null in copyitem.
How can I get particular column from the whole row.
You will have to bind the ItemsSource of DataGrid to CustomerDetails collection in order to get CustomDetails in SelectedItem.
Create property in your viewmodel (if using MVVM) or in code behind like
List<CustomerDetails> customerDetails = new List<CustomerDetails>();
List<CustomerDetails> MyCollection
{
get
{
return myList;
}
set
{
myList = value;
PropertyChanged(this, new PropertyChangedEventArgs("MyCollection"));
}
}
and in xaml just do.
<DataGrid ItemsSource="{Binding MyCollection}"/>
OR if you are directly filling the Items in the datagrid add instances of CustomerDetails like
dataGrid.Items.Add(new CustomerDetails(){Name = "abc"}, xyz propertis)
Thanks
If you can access the grid from your selection event then following should give your the column
((DataGrid)sender).CurrentCell.Column.Header
and use some mapping for the column name to the property of the object your want to show
I came up with this easy solution.
Mapped datatype of copyitem that was Anonymous in my case. In this case using Dynamic datatype solved my problem.
Due to my data was coming dynamically and then i was trying to map out particular column, so it was not really possible to do it statically because there is not data then.
Using Dynamic Datatype-
dynamic copyitem = dataGrid1.SelectedItem;
Accessing property-
int localId = copyitem.ID;
furthermore for customerName,TotalAmount i did the same.
Linq Query changes-
var query= (from order in db.Customer
where order.ID=localId
select order).ToList();
DataGrid_OpenSale.ItemsSource=query // returning data to another datagrid.
in VB ⠀⠀⠀
Private Sub SCUSTDataGrid_GotFocus(sender As Object, e As RoutedEventArgs) Handles SCUSTDataGrid.GotFocus
Dim og As DataGridCell = e.OriginalSource
Dim ccontent As TextBlock = og.Content
Dim dg As DataGrid
dg = e.Source
Dim selcol As String = dg.CurrentCell.Column.Header.ToString
MessageBox.Show(selcol.ToString + ccontent.Text + " got focus event")
End Sub