datagridview datasource not binding when change - c#

My code works fine but when I add data to datagridview it not binding to gridview. I didn't understand. When I search some I find BindingSource.If ı use this I have to change lots of things of my code. are there some shortcuts of binding to datagridview
This is loading datagridview
schoolGridView.DataSource = load.GetDataSource();
And this is when I adding row.
List<DataSourceObject> src = (List < DataSourceObject >)schoolGridView.DataSource;
DataSourceObject dat = new DataSourceObject();
dat.sinif = "asd";
dat.okulAdi = "ad";
dat.ogrenciAdi = "123";
dat.ilce = "43";
dat.il = "123";
src.Add(dat);
schoolGridView.DataSource = src;

Have you ever tried BindingList<> generic class that are simillar to List<> class? BindingList are more suitable for role of DataSource. I belive you can also benefit from methods like GridView.Invalidate(), GridView.Update() and GridView.Refresh(). You can find more information in DataGridView class.

Related

How to bind Fields to DataGrid in WPF?

I am programming UI with WPF for a month. So i am new in this world. This is my first ever post here and my motherlanguage isn't English. So if there is any mistake in my writing, sorry for that.
I have a problem with WPF and I am not able to find a solution for it. I am trying to make completely customizable DataGrid in WPF and I don't want the DataGrid to create columns or rows automatically.
I have an ObservableCollection named Sinif_Tutucu (means Class_Holder in my motherlanguage) which holds classes. These classes have the same Field and Properties, but their values are different. I am creating the columns one by one according to Fields and Properties in these classes. After this I am adding columns to DataGrid manually.
Then I am adding the rows with ItemsSource like this.
DataGrid_1.ItemsSource = Sinif_Tutucu;
This populates only properties in the DataGrid and columns made up of fields remain empty. I have searched this and i guess there is no way to bind Fields to DataGrid. Classes within Sinif_Tutucu have thousands of fields. So I can't turn fields to properties and I don't want to code the whole datagrid structure from scratch. Because WPF DataGrid structure offers many useful features which i am currently using. I am able to get Field names and their values or Property names and values. I just need to create each row myself (like columns) and populate their cells one by one with my hand with C#. Or somehow I need to convert these Fields to Properties programmatically. Is there any way to achieve this?
Supposing your class that you want to show in the datagrid looks like this
public class Data
{
public int Value;
public string Name;
public DateTime Date = DateTime.Now;
}
Because you cannot bind fields to DataGridColumns, you have to dynamically create the columns and the records. Here is a short snippet which you can use to do that. This method creates new dynamic objects in a List, which stores the same data as in your ObservableCollection. This List is set as the new ItemSource of your DataGrid. This snippet only creates DataGridTextColumns. You migth have to modify this solution, if want to use other DataGridColumns.
private void loadDataGrid()
{
List<dynamic> dataObjects = new List<dynamic>();
dynamic dataObject;
IDictionary<string, object> dataObjectValues;
var fields = typeof(Data).GetFields();
foreach (var item in Sinif_Tutucu)
{
dataObject = new System.Dynamic.ExpandoObject();
foreach (var field in fields)
{
dataObjectValues = (IDictionary<string, object>)dataObject;
dataObjectValues[field.Name] = field.GetValue(item);
}
dataObjects.Add(dataObject);
}
dataObjectValues = (IDictionary<string, object>)dataObjects[0];
foreach (var pair in dataObjectValues)
{
var binding = new Binding(pair.Key);
DataGridTextColumn col = new DataGridTextColumn() { Binding = binding, Header = pair.Key }; //You might want to use another DataGridColumn-Type
dataGrid.Columns.Add(col);
}
dataGrid.ItemsSource = dataObjects;
}

Datagridview - Quicker way to populate with List loop?

Currently, I'm planning to add ~500K List to datagridview.
Class has multiple Fields, Each List has 13 fields.
but i bind only 7 fields for now.
Problem is,it seems like adding takes too much time. like 5sec for 15K which is awful.
Is there any ways to optimze this?
or should i throw away datagridview and consider some other views?
private void UpdateDataGrid()
{
this.dataGridView1.Rows.Clear();
for (int i = 0; i < gVar.gTagCount; i++)
{
this.dataGridView1.Rows.Add(new object[]
{
gVar.Tags[i].TagCount,
gVar.Tags[i].Name,
gVar.Tags[i].Score.Story,
gVar.Tags[i].Score.Drawing,
gVar.Tags[i].Score.Drawing,
gVar.Tags[i].Score.Memetic,
gVar.Tags[i].DupeCount
});
}
}
According to what we discussed my approach would be this:
First make a new Class, I would call it TagsMin this class should contain the 7 things you want in your datagridview.
Secondly i would populate that a list of that class like this (you need to complete it with what you want):
var tagList = gVar.Tags.Select(x => new TagsMin() { TagCount = x.TagCount, Name = x.Name... }).ToList()
And the last step, would be to bind it to the datagridview:
dataGridView1.DataSource = tagList;
Consider using paging so that you are not loading all of the data at once. The answer to the question linked to below provides an example.
How can we do pagination in datagridview in winform
Can you try to avoid the loop and directly bind the list with the standard way:
dataGridView1.DataSource = null;
dataGridView1.DataSource = gVar.Tags;

How do I update a pre-formatted DataGridView bound to a list?

I have a DataGridView that I am binding to the Values collection of a dictionary. In my form's constructor, I can create the dictionary and bind the columns of the DataGridView to fields in the structure that will be contained in the dictionary:
m_tasks = new Dictionary<int,OperationsTaskLabeledData>();
var taskArray = from task in m_tasks.Values select new {
StartDate = task.m_start_task_date.ToString("M/dd H:mm"),
EndDate = task.m_task_date.ToString("M/dd H:mm"),
Description = task.m_short_desc,
Object = task.m_device_id,
InitialLocation = task.m_initial_location,
FinalLocation = task.m_final_location };
dgvFutureTasks.DataSource = taskArray.ToArray();
I want this code in the form's constructor so that the columns can be formatted, and I won't have to reformat them every time data in the grid is updated.
When I actually have data to display in this datagridview, what do I do with it? I will call this function:
private void DisplayFutureTasks(IEnumerable<OperationsTaskLabeledData> tasks)
But I don't know what to do inside this function.
I can just re-bind the datagridview control and reformat all of the columns each time the control is updated, but that seems very wasteful. I'm sure there's a better way to do it, and I'd much rather do this in some reasonable fashion instead of using ugly brute force.
I have now figured out how to do what I want to do.
I know the columns I will need at design time, so in the IDE I add the columns to my datagridview and format them as desired. I then set the AutoGenerateColumns property of the grid view to false. For some unknown reason, that property is not available in the designer and has to be set in code. Finally, I can set the DataPropertyName of each column to the name of the corresponding field in the structure I will be linking to. For example, here is the LINQ code I will be using to generate the data source:
taskArray = from task in tasks select new {
StartDate = task.m_start_task_date.ToString("M/dd H:mm"),
EndDate = task.m_task_date.ToString("M/dd H:mm"),
Description = task.m_short_desc,
Object = task.m_device_id,
InitialLocation = task.m_initial_location,
FinalLocation = task.m_final_location };
.DataSource = taskArray.ToArray();
And here is the code in my form's constructor to set the DataPropertyName properties:
dgvFutureTasks.AutoGenerateColumns = false;
dgvFutureTasks.Columns["colStartTime"].DataPropertyName = "StartDate";
dgvFutureTasks.Columns["colFinishTime"].DataPropertyName = "EndDate";
dgvFutureTasks.Columns["colDescription"].DataPropertyName = "Description";
dgvFutureTasks.Columns["colObject"].DataPropertyName = "Object";
dgvFutureTasks.Columns["colInitialLocation"].DataPropertyName = "InitialLocation";
dgvFutureTasks.Columns["colFinalLocation"].DataPropertyName = "FinalLocation";
At this point, the DataGridView displayed the data as expected.
RobR

Binding BindingList<string[]> to datagridview

Situation:
I am attempting to bind a BindingList<string[]> constructed from a LINQ to SQL query to a DataGridView.
Problem:
I either cannot make modification to the DataGridView after items are generated -or- I get a bunch of unwanted fields in my DataGridView (it depends on which iteration of my code I use) I have googled as hard as I can and tried implementing most of the solutions I have found online to no avail.
I know that string has no public property for its actual value. I am having a difficult time determining how to retrieve that (I believe is part of the problem).
C#
int item = (from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].Modules
where p.ModuleName.Equals(clbModules.SelectedItem)
select p.ModuleId)
.FirstOrDefault();
BindingList<string[]> Data = new BindingList<string[]>((
from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].QuestionAnswers
where p[2].Equals(item)
select new string[] { p[0].ToString(), p[3].ToString() })
.ToList());
dgvQuestions.DataSource = Data;
dgvQuestions.Refresh();
Unwanted Behavior:
This occurs after binding
Question:
Why is this happening?
How do I fix it?
Additional Information:
I am not sure what additional information may be need but I will supply what is requested.
Also if I switch to my other code iteration:
int item = (from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].Modules where p.ModuleName.Equals(clbModules.SelectedItem) select p.ModuleId).FirstOrDefault();
var Data = new BindingList<object>((from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].QuestionAnswers where p[2].Equals(item) select new {Question = p[0].ToString(), Answer = p[3].ToString() }).Cast<object>().ToList());
dgvQuestions.DataSource = Data;
dgvQuestions.Refresh();
dgvQuestions.Columns[1].ReadOnly = false;
I can see the data properly but I cannot edit the column I would like to.
You are binding to a list of string arrays, and you are getting the properties form the array. Most likely you want something like the following:
var Data = new BindingList<object>((
from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].QuestionAnswers
where p[2].Equals(item)
select new {
Val1 = p[0].ToString(),
Val2 = p[3].ToString()
}).ToList());
The reason you're seeing those fields in the Grid is that you're binding each row to a string[]. So it is automatically displaying the properties of string[] as the columns. There is no built-in logic for the grid to parse an array and use the contents of the array as columns.
In order to get the DataGrid to display your data correctly, you should bind it to a custom type, and it will use the public properties of the type as columns.

Unbound GridControl

I have a gridControl who's data source is a List.
Each item in List is made out of three fields.
And I have 3 columns in the gridControl.
when I programatically insert values into the gridview it does not appear.
Here is my code.
public Company_Selection()
{
InitializeComponent();
companies = new List<DataLibrary.Companies>();
gridControl1.DataSource = companies;
}
internal void load_all_companies(List<DataLibrary.Companies> other)
{
for (int i = 0; i < other.Count; i++)
{
companies.Add(other[i]);
gridView1.SetRowCellValue( i, "Id", other[i].id);
gridView1.SetRowCellValue( i, "Company", other[i].name);
gridView1.SetRowCellValue(i, "Description", other[i].description);
gridView1.RefreshData();
gridControl1.RefreshDataSource();
}
}
Any ideas about what's wrong ?
The thing is you should not work with cells directly. Your 'companies' list should be enclosed in BindingList. All programmatical changes are done at object, not grid level. So, setting datasource becomes
gridControl1.DataSource = new BindingList<DataLibrary.Companies>(companies);
This will take care of presentation, changes, additions and deletions of objects within list. The columns will be created automatically if your gridView does not contain any and AutoPopulateColumns is true. You might want to setup columns in gridView using Designer. Don't forget so set Field property to Property name of underlying object.
You correcly set the datasource property, but you have also to bind the datasource to the control by using the DataBind method like this
gridControl1.DataSource = companies;
gridControl1.DataBind();
I think you for get to write DataBind method
gridControl1.DataBind();
so you code will be
companies = new List<DataLibrary.Companies>();
gridControl1.DataSource = companies;
gridControl1.DataBind();
GridView.DataBind Method
: Binds the data source to the GridView control.
Use the DataBind method to bind data from a data source to the GridView control. This method resolves all data-binding expressions in the active template of the control.
I believe the cause of the issue is that you are using fieldnames like "Id","Company", "Description" but the grid is mapped on "id","name","description" fieldnames:
gridView1.SetRowCellValue( i, "Id", other[i].id);
gridView1.SetRowCellValue( i, "Company", other[i].name);
gridView1.SetRowCellValue(i, "Description", other[i].description);
Also passing row cell values directly to a view and refreshing the grid after appending every record is very redundant. The single RefreshDataSource method call after data loading is only enough:
internal void load_all_companies(List<DataLibrary.Companies> other) {
for(int i = 0; i < other.Count; i++)
companies.Add(other[i]);
gridControl1.RefreshDataSource();
}

Categories