How to specify a data object for a WinForms datagridview in code? - vb.net

I created a class with public properties and added it as a new DataSource object in a WinForms project.
Public Class ICS211DetailCols
Public Property ID As Integer
Public Property fk211 As Integer
Public Property StateAbbreviation As String
...
End Class
When I add a DataGridView control to a Form from the ToolBox, the DataSource property can be set to the BindingSource created by the DataSource object (ex. ICS211DetailColumnsBindingSource) by selecting it from the Other Data Source ComboBox and all columns will appear in the DataGridView Columns collection.
I would now like to create a DataGridView in code and associate the same BindingSource but cannot seem to find any information on how this is accomplished. Is this even possible to do in code, or must I add the columns to the collection individually?

Related

find an object in a bindinglist by a property of the object

I have a class inheriting bindinglist.
Public Class clsCustomerPurchaseOrders
Inherits BindingList(Of clsCustomerPurchaseOrder)
I have some code that updates a DataGridView row with values entered by a user. I know the id of the clsCustomerPurchaseOrder thats been changed and I know that the bindinglist has been updated with the values.
How do I search the bindingList to find the clsCustomerPurchaseOrder with the id I have, so I can return that clsCustomerPurchaseOrder object for further work?
Do I have to iterate though all the ClsCustomerPurchaseorders in the bindinglist to find the right one or is there a find/search function?
thanks!

Binded DataGridView only updating the currently selected row

I'm working on getting my DataGridView controls to auto update the values of my objects in my object model. I have object arrays that I'm binding to my DataGridView through the following code
Dim bs As BindingSource = New BindingSource()
bs.DataSource = aryJoints
DataGridJoints.DataSource = bs
I am raising events in the object model using INotifyPropertyChanged.
The following is in my "Public Class Joint"
Implements System.ComponentModel.INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
And in the GoalPosition property I have the following:
Private _GoalPosition As Double
Property GoalPosition() As Double
Get
Return _GoalPosition
End Get
Set(ByVal Value As Double)
_GoalPosition = Value
RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("GoalPosition"))
End Set
End Property
If I update the property aryJoints(0).GoalPosition from the same form or other forms the DataGridView will only update the GoalPosition field in the DataGridView when that row is selected. If I'm on a different row and then move onto the row that had a change, then the row updates with the latest values.
From my understanding, once I've done proper binding with events being raised any cell should auto update with new values. I shouldn't have to be in that cell, or have that row selected for the form to reflect the changes.
If I call DataGridJoints.Refresh() the DataGridView updates all values as it should. But the whole point of creating binded DataSources is to avoid the need to call .refresh. There will be many forms and operations updating the object model from different places and I need the DataGridViews on the various forms to auto update themselves.
What am I missing a step or doing wrong?
As suggested in the comments above to try switching over to BindingList instead of using a binded array. I tested this solution and it works. The DataGridView updates as needed on any row when the object model has updated values. So I will implement this change in the code :)

Populate multiple comboboxes from 1 ienumerable

Good afternoon,
Is there a way to divide a ienumerable and bind all the different values to the different comboboxes.
Like you can see in the picture below:
I got 10 comboboxes, while the input of these all come from 1 ienumerable.
I do have an option to do a for each and go through the entire database, and add them to the combobox with:
Dim ts As IEnumerable(Of tblLabel)
For Each itms In ts
CmbDescription.Items.Add(itms.Description)
CmbLabelId.Items.Add(itms.LabelID)
...
Next
But I wonder if I can link the different 'columns' of the Ienumerable directly to the datasource of the associated comboboxes.
I'm searching for an option like:
CmbDescription.DataSource = ts.Description
CmbLabelId.DataSource = ts.LabelId
...
Sadly enough, this ienumerable can't be splitsed like this, as far as I can see.
Another workaround would be to create all separate ienumerables for all those comboboxes, but then it is too much code.
Any idea?
I think your original approach is good enough.
But if you want populate ComboBoxes by separated collection of items using DataSource property, then you can simply get needed collection from IEnumerable
CmbLabelId.DataSource =
ts.Select(function(label) label.LabelId).Distinct().ToList()
CmbDescription.DataSource =
ts.Select(function(label) label.Description).Distinct().ToList()
But in this approach you will loop IEnumerable as much times as how much ComboBoxes you have.
Here is my approach, but again want to say that your original approach is simple enough.
' In this class will be collected all distinct value of all columns
' Create own property for every column which used in the ComboBoxes
' With HashSet only distinct values will be collected (thanks to #Ivan Stoev's comment)
Public Class TblLabelProperties
Public Property LabelId As New HashSet(Of Integer)
Public Property Description As New HashSet(Of String)
' Other properties/columns
End Class
' Populate collections from database
Dim ts As IEnumerable(Of tblLabel)
Dim columnsValues As TblLabelProperties =
ts.Aggregate(New TblLabelProperties(),
Function(lists, label)
lists.LabelId.Add(label.LabelId)
lists.Description.Add(label.Description)
'Add other properties
Return lists
End Function)
' Set DataSources of comboboxes
CmbLabelId.DataSource = columnsValues.LabelId.ToList()
CmbDescription.DataSource = columnsValues.Description.ToList()
One way to implement this without putting each data source to each ComboBox is by implementing mapping between the column name in DataGridView.Columns and the combo box name ComboBox.Name.
This can be done by using Dictionary so for each column name, you map to specific ComboBox. Then, you can do the populating by foreach or for loop.
Yet, it might still be preferable in some cases that you really take each ComboBox having its own data source

Adding a new entity to a bound DataGridView

I have Companies and Contracts in a parent-child relationship, shown in two DataGridViews in a winforms app. They are both bound to collections of Entity models.
How can I add a new contract?
If I do this,
Dim c as Company = CompaniesBindingSource.Current
c.contracts.Add(New Contract())
context.SaveChanges()
the grid doesn't refresh (even if I call .Refresh(), or .ResetBindings() on the BindingSource. I have to navigate away from the selected company and back to it, for the grid to refresh.
If I do ContractsBindingSource.AddNew(), the grid refreshes, but the data doesn't persist to my entity context.
Note: my contracts collection is a property on my Company model:
Public ReadOnly Property activeContracts As SortableBindingList(Of Contract)
Get
Dim list = New SortableBindingList(Of Contract)
For Each contract As Contract In contracts.Where(Function(c) c.isActive).ToList
list.Add(contract)
Next
Return list
End Get
End Property
Does this have anything to do with it? How can I force a property to recompute?
This worked for me:
CompaniesBindingSource.ResetCurrentItem()
This recalculated the Contracts property, and automatically refreshed the contracts grid.

Using list of custom Class object as data source for crystal report

I am trying to find way to design a report using my own custom class.
I found links:
1.) How to work in Crystal Report with Object Data Source?
2.) Use .net object as data source in Crystal Report 2008
3.) Binding object with List<> to Crystal Report
4.) How to assign Custom class as datasource in crystal report
They were quite helpful, but I have been stuck in the first step while designing report as my custom class's property is not listed in field list of crystal report design view.
Sample of my Custom Class:
class UserType
public property UIN as integer...
public property Title as string...
end class
class User
public property UIN as Integer...
public property Name as string...
public property Password as String...
public property Type as UserType...
end class
When I add my class objects to crystal report I do not get the usertype field from users class in field list.
So how can I add usertype field to my field list? Or do I have to take another approach?
Edit:
The reason i wanted to use it as i am:
1.) Showing a form where user can type keyword
2.) program filters the records as per keyword using LINQ
3.) when user clicks the print button, I want to set the filtered records as datasource of my report
Create your dataset with the columns matching your class, and assign
the dataset to your report normally.
When you have your object class loaded with data, and/or filtered with values entered by users (filtered with linq etc..)
do this:
dim yourDataset as dataset ' this is your typed dataset
Dim dr As datarow
For n As Integer = 0 To yourClass.Count - 1
dr = yourDataset.tables("TableName").NewRow
dr("ColumnNameOne") = yourClass(n).PropertyName
dr("ColumnNameTwo") = yourClass(n).PropertyName
yourDataset.tables("TableName").Rows.Add(dr)
Next
' bind the datasource
crystalreport.SetDatasource(ds)
You could try serializing the object to XML, supply an XSD, then use Crystal Report's XML driver to connect to it. The report will 'see' the object as two tables: one for the User and one for UserType. You'll include both 'tables' in the report and link the tables using the internal_id field.
Why don't you assign a strongly typed dataset to your report and save yourself lots of trouble?