How can I get gridcontrol records as an array?
I set an array as a datasource for a gridcontrol (devExpress component).
PersonFamily4grid[] tmpPersonFamily = new PersonFamily4grid[PersonFamiliesCOUNT];
for (int i = 0; i < PersonFamiliesCOUNT; i++)
{
tmpPersonFamily[i] = new PersonFamily4grid();
tmpPersonFamily[i].BirthDate = PersonFamilies[i].BirthDate;
tmpPersonFamily[i].Job = PersonFamilies[i].Job;
tmpPersonFamily[i].CodeMelli = PersonFamilies[i].CodeMelli;
tmpPersonFamily[i].NameFamily = PersonFamilies[i].NameFamily;
tmpPersonFamily[i].Nesbat = FamilyInfo_cbe_Nesbat.Properties.Items[PersonFamilies[i].Nesbat].ToString();
tmpPersonFamily[i].Taahol = FamilyInfo_cbe_Taahol.Properties.Items[Convert.ToInt32(PersonFamilies[i].Taahol)].ToString();
}
grid_Family.DataSource = tmpPersonFamily;
Now when the user changes data in gridcontrol, I want to get changes from the grid and affect my base array.
When user changes data in gridcontrol i want get changes from grid and
affect my base array.
Why are you creating temporary array if you want to reflect changes to main array PersonFamilies. just simply assign PersonFamilies to gridControl's data source and it will automatically reflect changes to PersonFamilies.
If you know that class object are reference type, so their reference will not change if you assign the array directly to the gridControls data source as:
grid_Family.DataSource = PersonFamilies;
After making some changes to your data in grid view, check the object of PersonFamilies array that they are updated or not. It will surely update the array of objects.
If you want to work on some customized Data that contained in your PersonFamilies array then you can get the Iterate your temporary array tmpPersonFamily without getting it through the DataSource property of GridControl and it all depends on you how you will manipulate or reflect changes to your main array PersonFamilies.
e.g.
for (int i = 0; i < PersonFamiliesCOUNT; i++)
{
PersonFamilies[i].BirthDate = tmpPersonFamily[i].BirthDate;
PersonFamilies[i].Job = tmpPersonFamily[i].Job;
PersonFamilies[i].CodeMelli = tmpPersonFamily[i].CodeMelli;
PersonFamilies[i].NameFamily = tmpPersonFamily[i].NameFamily;
}
Hope this help..
Try:
PersonFamily4grid[] personFamily = (PersonFamily4grid[])grid_Family.DataSource;
Related
This is a C# Windows Forms project. I have a grid on a form. To get the data for the grid, I run a SQL procedure and store the results in a class. I want to have a copy of that class so I know what the values were before the user changes them in the grid. So I assign the class to another class. Then I assign the first class as the grid's datasource. However, after the change is made, both the original class and the copy have the same values. How do I prevent this?
Here's is my code:
List<Unreceive> receivedItems = new List<Unreceive>();
List<Unreceive> listItems = mpBLL.GetMPItemsReceived();
receivedItems = listItems;
gcUnreceive.DataSource = listItems;
at this point, let's say receivedItems.quantity and listItems.quantity have a value of 100.
The user changes the data in the grid so the quantity is 50. That triggers this code:
private void gvUnreceive_CellValueChanged(object sender, DevExpress.XtraGrid.Views.Base.CellValueChangedEventArgs e)
{
DevExpress.XtraGrid.Views.Grid.GridView gridView = (DevExpress.XtraGrid.Views.Grid.GridView) sender;
int index = gridView.GetDataSourceRowIndex(rowHandle);
Unreceive selectedItem = listItems[index];
Unreceive originalItem = receivedItems[index];
int newQuantity = selectedItem.quantity;
int originalQuantity = originalItem.quantity;
}
At this point I want:
newQuantity = 50;
originalQuantity = 100;
But what I get is:
newQuantity = 50;
original Quantity = 50;
It's like I passed a variable by reference instead of by value, but I haven't passed it anywhere. How do I fix this so that the receivedItems class isn't effected by what happens to the listItems class or the datagrid?
Yes you are right that it seems "byRef"
receivedItems = listItems;
"object = object" would share the Pointer to where the data is not create a new pointer to a new data structure.
You were on the right track in creating a new list initially.
List receivedItems = new List();
You need to loop through your original list and create new distinct list items for the copy list - setting each property to the value of the master list. This will give you two lists with separate memory storage.
I wish for my ListBox to update the old values with new values rather than simply adding more and more lines to the ListBox like it does at the moment. However, I'm not sure where to look to implement something that can handle this.
My current code looks like this:
private void DisplayText(string rawData)
{
textArduinoData.Text = rawData;
string[] sortedData = rawData.Split(';');
for (int i = 0; i < sortedData.Length; i++)
{
listPortData.Items.Add(sortedData[i].ToString());
}
}
Could someone please point me in the right direction to implementing this update feature? Any advice would be much appreciated.
You need to manage the process. It is easy in concept but depending on how much data is needed to be processed, it could get slow quickly. Steps
Create a specialized token class which implements to INotifyPropertyChanged.
Have an ObservableCollection hold the class items from #1. The observable collection notifies the ListBox when an item is added or removed. This will allow your code to add items one at a time. (Solves 1 problem)
To solve the next problem of data changing: Have a property named Text, on the class in #1 which will hold the data, provide a property change notification.
In the list box bind to the list of items created in step 1 and specify to bind to the Text. Use of a data template for the listbox will allow you to bind to the Text property of the list's instance.
Provide the heuristics/ smarts to read incoming data and find the associated data in the observable collection from step 2. When found change the Text property of the existing data to the new and the binding of that list item will change accordingly.
You could check if the ListBox contains the string using the IndexOf method and then update the existing string (or simply do nothing) or add a new one depending on whether you get an index other than the default value of -1 back:
private void DisplayText(string rawData)
{
textArduinoData.Text = rawData;
string[] sortedData = rawData.Split(';');
int index;
for (int i = 0; i < sortedData.Length; i++)
{
if ((index = listPortData.Items.IndexOf(sortedData[i])) == -1)
{
listPortData.Items.Add(sortedData[i]);
}
}
}
I've created a software with a datagridview. It can save all data from datagridview.But the problem is data, if a user don't insert data in one cell, software will crash. How i can verify this ? I save dgv content with this code :
//Write in file
StreamWriter ecriture = new StreamWriter(tes, true);
for (int i = 0; i < dataGridView1.Rows.Count-1; i++)
{
for (int j = 0; j < dataGridView1.Columns.Count; j++)
{
ecriture.Write("\t"+dataGridView1.Rows[i].Cells[j].Value.ToString()+"\t"+"|");
}
ecriture.WriteLine("");
}
ecriture.Close();
I hope you can help me :)
Thanks from France
You should create a data model, just a class that contains properties which are corresponding to your data grid columns.
public class MyModel {
public string prop1 {get;set;}
}
Then bind BindingList<MyModel> to your grid like that:
dgv.DataSource = myList;
And then use that list of objects to obtain data fro grid as oppose to reading text or value from cells.
You can always check if cells has VALUES etc, but that not very Object Oriented approach and also very hard to maintain as code change when you want to reorder columns.
Something to read:
https://msdn.microsoft.com/en-us/library/y0wfd4yz(v=vs.110).aspx
Binding List<T> to DataGridView in WinForm
If you still want to go your way, make sure that all elements of that chain are not nulls.
dataGridView1.Rows[i].Cells[j].Value.ToString()
If Row with that index doesn't exist, there is IndexOutOfRangeException, same for column with given index. If cell exists but is empty, its Value is NULL and then you get NullReferenceException because you can't do ToString on null object.
I have a DataGridView in winforms, that contains a combobox column. The gridview is filled programmatically, and it is empty at start. "list" is a list containing custom objects. Value1/2/3 are unique to each row.
int[] array = new[] {value1,value2,value3}
for (int i = 0; i < list.Count; i++)
{
DataRow newrow = MyDataTable.NewRow();
newrow["idColumn"] = list[i].Customer_id;
newrow["dateoforderColumn"] = list[i].Customer_date;
newrow["commColumn"] = list[i].Customer_comment;
// This is what I want, and can't get to work.
newrow["comboColumn"] = array;
// I have also tried (newrow["comboColumn"] as DataGridViewComboColumn).DataSource
// but it didn't work either.
MyDataTable.Rows.Add(newrow);
}
How can I populate a freshly created combobox cell? Also, I need to do it within the for loop, because I need the index to get the data.
From the look of your code you just have one array of values that you need to set. In this case you only need to set it once for the column, not for every row, i usually do this in the constructor or before populating rows.
//Clear any junk items that may have been there from the designer or previous view
((DataGridViewComboBoxColumn)MyDataTable.Columns["comboColumn"]).Items.Clear();
//Add you new values
((DataGridViewComboBoxColumn)MyDataTable.Columns["comboColumn"]).Items.AddRange(array);
Then to set the value of the new row's cell
//Set value to be selected in new row
newrow["comboColumn"] = list[i].Customer_value;
I'm using the ObjectListViewand am trying to add images to my items. I got it to work by looping through all the items and then manually editing the image index per item. I would like to know if this is possible when adding the items. This is the code I have at the moment:
Adding the items
for (int i = 0; i < listName.Count; i++)
{
games newObject = new games(listName[i], "?");
lstvwGames.AddObject(newObject);
}
Adding the images
foreach (string icon in listIcon)
{
imglstGames.Images.Add(LoadImage(icon)); // Download, then convert to bitmap
}
for (int i = 0; i < lstvwGames.Items.Count; i++)
{
ListViewItem item = lstvwGames.Items[i];
item.ImageIndex = i;
}
It is not entirely clear to me what exactly you try to achieve, but there are several ways to "assign" an image to a row. Note that you probably have to set
myOlv.OwnerDraw = true;
which can also be set from the designer.
If you have a specific image for each of your model objects, its probably best to assign that image directly to your object and make it accessible through a property (myObject.Image for example). Then you can use the ImageAspectName property of any row to specify that property name and the OLV should fetch the image from there.
myColumn.ImageAspectName = "Image";
Another way to do it is using the ImageGetter of a row. This is more efficient if several of your objects use the same image, because you can fetch the image from anywhere you want or even use the assigned ImageList from the OLV by just returning an index.
indexColumn.ImageGetter += delegate(object rowObject) {
// this would essentially be the same as using the ImageAspectName
return ((Item)rowObject).Image;
};
As pointed out, the ImageGetter can also return an index with respect to the ObjectListView's assigned ImageList:
indexColumn.ImageGetter += delegate(object rowObject) {
int imageListIndex = 0;
// some logic here
// decide which image to use based on rowObject properties or any other criteria
return imageListIndex;
};
This would be the way to reuse images for multiple objects.
Both your approach and the one I show below will have problems if the list is ever sorted as sorting will change the order of the objects in the list. But really all you have to do is keep track of your object count in your foreach loop.
int Count = 0;
foreach (string icon in listIcon)
{
var LoadedImage = LoadImage(icon);
LoadedImage.ImageIndex = Count;
imglstGames.Images.Add(LoadedImage); // Download, then convert to bitmap
Count++;
}