Unbound GridControl - c#

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();
}

Related

datagridview datasource not binding when change

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.

ComboBoxes are linked (and that is bad)

I am doing simple WinForms application, and I am facing some strange problem.
My form:
It is as easy as it can be: 3 comboboxes, and two buttons - OK and Cancel.
View:
private void applyOrderButton_Click(object sender, EventArgs e)
{
List<string> testList = new List<string>()
{
"A",
"B",
"C"
};
comboBox1st.DataSource = testList;
comboBox2nd.DataSource = testList;
comboBox3rd.DataSource = testList;
comboBox1st.SelectedIndex = 2;
comboBox2nd.SelectedIndex = 1;
comboBox3rd.SelectedIndex = 0;
//Presenter.DoTest();
}
What happens after caling method applyOrderButton_Click() (it happens after Ok button is clicked) all of my comboBoxes change selected position. However, each of those comboBoxes have the same selected index - in this particular case it will be "A".
Then I change change comboBox selectedIndex using my cursour (for example I choose 3rd comboBox to show "C") the change is performed for all three comboBoxes. What I am doing wrong?
You are running across something that is present in the background of WinForms called the "CurrencyManager".
Its job is to synchronize the "current record" across all bindable controls that refer to the same data source.
For instance, if you had added a label and bound it to the same list, and bound it so that it shows a property of one of the objects, it would always show the property value of the same object you had selected in the combobox.
One bonus of this is that you could easily add a form that edits a list of objects, binding textboxes and such to the properties of one of the objects and adding a navigator that allows you to move to the next or previous row. You would not have to manually ensure all textboxes refer to the correct object, the CurrencyManager would do all this for you.
However, in your case, since you bound the same data source to all three comboboxes, the CurrencyManager will ensure all three select the same row. If you select a new row in one of the comboboxes, the CurrencyManager will go and fix all the others to refer to the same row.
You can fix this in various ways:
You can override the binding context for each combobox:
comboBox2nd.BindingContext = new BindingContext();
comboBox3rd.BindingContext = new BindingContext();
Note that if you go this route you need to do this before assigning the SelectedIndex or SelectedItem properties, otherwise the CurrencyManager will have updated the other two comboboxes before you assigned new BindingContexts.
You can assign distinct data sources to each combobox:
combobox2nd.DataSource = testList.ToList();
combobox3rd.DataSource = testList.ToList();
Just assign new context to other ComboBoxes like that:
List<string> testList = new List<string>()
{
"A",
"B",
"C"
};
comboBox1st.DataSource = testList;
comboBox2nd.BindingContext = new BindingContext();
comboBox2nd.DataSource = testList;
comboBox3rd.BindingContext = new BindingContext();
comboBox3rd.DataSource = testList;
comboBox1st.SelectedIndex = 2;
comboBox2nd.SelectedIndex = 1;
comboBox3rd.SelectedIndex = 0;
The CurrencyManager is used to keep data-bound controls synchronized with each other (showing data from the same record). The CurrencyManager object does this by managing a collection of the bound data supplied by a data source. For each data source associated with a Windows Form, the form maintains at least one CurrencyManager. Because there may be more than one data source associated with a form, the BindingContext object manages all of the CurrencyManager objects for any particular form. More broadly, all container controls have at least one BindingContext object to manage their CurrencyManagers.

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

How do you bind a data field value to a combobox index?

This may have been already asked but I can't seem to find this specific question, so here goes...
I have a form in C# where every textbox is bound to a field in a row. Rows can be cycled through by some buttons on the bottom but all the data displayed at a time in the from is from one row. Any changes that are made get updated back to the database when the user clicks "update"
One field (class) is an enumeration (0,1,2) where only the value is stored in the database, but doesn't mean much to the user. I was asked to make this more obvious to the user, so I decided to go with a dropdown style combo box. Since the database didn't have any reference to what the values meant, I decided to use the DataBindings instead of DataSource so I could just use the index as the data bind, but it seems that SelectedItem or Value are not the way to do this.
Here is my goal:
1 exists in database, so "B" is selected in combo box.
User selects "C" and updates the database, 2 is now stored in the database.
Any thoughts on what I need to get this working?
I assume you have a BindingSource on your form to bind to the data. You can bind the SelectedIndex property of the ComboBox as follows:
comboBox.DataBindings.Add("SelectedIndex", bindingSource, "PropertyInTheDataSource");
Actually I was able to bind it to a custom Object. It's a little too much work for such a simple task. But you have complete control on Display/Value pairs. Anyway, I thought I'd share and you decide:
Create a new class (say CustomItem) with 2 fields:
Public int Value{get;set;}
public string Title {get;set;}
Then in you form:
var item1 = new CustomItem() { Title = "A", Value = 10 };
var item2 = new CustomItem() { Title = "B", Value = 20 };
var item3 = new CustomItem() { Title = "C", Value = 30 };
var lst = new List<CustomItem>();
lst.Add(item1);
lst.Add(item2);
lst.Add(item3);
comboBox1.DataSource = lst;
comboBox1.DisplayMember = "Title";
comboBox1.ValueMember = "Value";
Now You have a databound combobox in case you don't have BndingSource in your form.
Just remember to define your class's Title and Value as properties otherwise it wouldn't work.

How do I Add a new row to a datagridview without using a dataset or datatable?

I'm using a List to bind to a dataGridView.
I'd like the user to be able to add a new row.
I've tried using a BindingList and a BindingSource.
Here's my binding (not including the combo box column I add to the datagridview before adding a datasource:
binding = new BindingSource();
binding.DataSource= _Rows;
_dg.DataSource = binding;
Here's the code that fills _Rows
protected override List<BusinessApp> getRows(DataGridViewManager manager)
{
var dc = manager.dc.DcHerb;
return (from p in dc.apps
where p.zQueueId == this.ZQueueId
select p)
.ToList().ToBusinessApp(dc);
}
Here's what I'm trying to get a new row. No exception occurs, but the dataGridView doesn't appear to change at all, even though _Rows count goes from 68 to 69
private void newRow()
{
_Rows.Add(new BusinessApp(_manager.dc.DcHerb, new app() {acaps="1234" }));
//_dg.DataSource = binding; //tried rebinding here
//_dg.DataSource = _Rows;
}
I would as if you have any foreign key bind to the other table or not, if yes, you may assign a key to the new added row and the datagrid will show the current new added row. Otherwise you may also missing the code datagrid.EndEdit()
How about invoking "AddNew()" method on your "binding" member variable that you have defined already?
binding.AddNew();
// and set the needed columns...
((binding.Current.Row) as <yourTypedDataTableRow>).<columnName> = <someValue>;

Categories