Entity with Winforms / bindingsource - can't save user input from controls - vb.net

I have a winforms program I am migrating to entity (EF5). The edit works okay. The add does not. The basic workflow is user can either add or edit an object. There is a list of comboboxes, text boxes, etc on screen for the user to input.
I have the entity bound to a binding source. I have the textbox bound to the bindingsource.
Add functionality looks like this.
If (mViewAddEdit = ViewAddEditEnum.Add) Then
Dim ps As New RADS.PHANTOM_SESSION
Me.bsPhantom.DataSource = db.PHANTOM_SESSION.Add(ps)
Me.EdtMuscleWater.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.bsPhantom, "MUSCLE_OR_WATER", True, DataSourceUpdateMode.OnValidation)) ' etc
End If
So that seems okay, but when user clicks ok button (to save).
drvPhantom = TryCast(Me.bsPhantom.Current, RADS.PHANTOM_SESSION)
' examining the object shows nothing bound.
If mViewAddEdit = ViewAddEditEnum.Add Then
db.PHANTOM_SESSION.Add(drvPhantom)
db.SaveChanges()
End If

The issue arose from the form blocking validation.
Me.AutoValidate was set to disable. So this blocked the binding source from updating even with a call to Me.Validate()
Also since I found it so hard. This is how to Add or Edit - controls bound to binding source using Entity EF5.
If (mViewAddEdit = ViewAddEditEnum.Add) Then
Me.bsPhantom.DataSource = New PHANTOM_SESSION
SetPhantomDataBindings()
Else
Dim query = From ps In db.PHANTOM_SESSION Where (ps.PHNTM_SESSION_NO = CDbl(mPhntmSessionNum))
bsPhantom.DataSource = query.ToList() ' resize occurs here
SetPhantomDataBindings()
...
End If
The other thing is if you are programmatically writing to the text box, ie textbox1.text = "foo" you must also update the underlying object.
CType(Me.bsPhantomBlock.Current, RADS.PHANTOM_BLOCK).OTHER_CORRECTION = CDec(val)
Here we are casting the current object of the binding source to its type (PHANTOM_BLOCK) then setting the field "OTHER_CORRECTION" to val.
Updating the binding source does not work as it causes all inputted user data to be thrown away. For example there are 5 text boxes (a,b,c,d,e). user enters 1,2,3,4,5 into those. The 5th is handled by bindingsource Write: textbox1.DataBindings(0).WriteValue - this will update the 5th field (e),but causes a,b,c,d to be blank as the are reverting to stored value. This is my experience anyway.

Related

Setting focus to another control prevents current control value from changing in VB.NET

I have a ComboBox in a WinForms app written in VB.NET. In the .SelectionChangeCommitted event I want to change the focus to a different specific control to assist user workflow. However when I do that, the change is not saved on the initial ComboBox and the value & index are reverted to the original values.
I've used both myControl.Focus and myControl.Select
The Combobox is setup like this:
With ChoosePartType
.DisplayMember = "PartName"
.DataSource = GetTable(qry) 'This custom function returns a DataTable with fields PartNum and PartName
.ValueMember = "PartNum"
.SelectedIndex = -1
End With
I assume something in the changing focus is short-circuiting the property change. Is there a way to force that to happen before I change focus?
Note: seems like a different issue from WInforms Combobox SelectionChangeCommitted event doesn't always change SelectedValue
Similar to this but I don't use databindings: Combobox DataBinding Bug - Won't write value if programmatically losing focus
Try using:
ChoosePartType.SelectedItem.Row("PartNum")
Assuming that this is the first column of the control's datasource, this could be also written as:
ChoosePartType.SelectedItem.Row(0)

Add data field from table to form automatically using vba

In an Access database, I have a split form. The datasheet is based on a query.
The table that is queried sometimes grows in fields.
This field is in the query, but not in the form because it has to be dragged from the "available fields" on design view on access into the form.
Is there some code that will allow a field to be added to a form when a button on the form is pressed instead of the user going into design view?
This would be more convenient than having every user opening and editing (possibly breaking) the database in design view.
As you can see from the comments, similar questions have been asked and so the default answer is that even with VBA code the form must be in design mode to add new controls - you cannot do this in Form View. But despite the limitations of Access there is still often a perfectly reasonable need that still requires a useful solution.
One potentially cluttered and limited solution is to add hidden unbound controls (i.e. ControlSource property is blank) that can then be bound and shown during Form View. First, during design time add hidden, unbound TextBox and Label controls to the form. Here is some template code within a button click event handler.
Private Sub cmdAddFields_Click()
Dim rs As Recordset2
Set rs = Me.RecordsetClone
Dim fld As Field2
...
'* Determine which new fields need to be shown
set fld = rs.Fields(missingFieldIndexOrName)
...
Me.txtCustom1.ControlSource = fld.Name
Me.lblCustom1.caption = fld.Name
Me.txtCustom1.Visible = True
Me.lblCustom1.Visible = True
...
End Sub
It should be apparent that you would be limited to the number of these dummy fields that you have added, and it'll require some clever way of determining what your missing fields are but that could be done by looping through the rs.Fields collection and the form's Control collection to match names (for instance).

Setting the value of cell in datagridview not working in form load

This is my code for setting the value in datagridview cell:
For i = 0 To dvJOBranch.Rows.Count - 1
dvJOBranch.Rows(i).Cells.Item("XS").Value = 0
dvJOBranch.Rows(i).Cells.Item("S").Value = 0
dvJOBranch.Rows(i).Cells.Item("M").Value = 0
dvJOBranch.Rows(i).Cells.Item("L").Value = 0
dvJOBranch.Rows(i).Cells.Item("XL").Value = 0
Next
Its working in button event, shown form event, but not in form load, and there are no errors.
My question is why it does not work in form load?
My guess is that you are using the DataGridView.AutoGenerateColumns functionnality and even if you set the DataSource property, the DatagridView won't create columns until the grid is displayed.
It could explain why it's not working in formload (grid is not initialized yet) and it works after (with shown event for example).
So it's possible that:
you try to access items that do not exist yet (but the code should raise an exception)
or you access valid rows or columns, but they are replaced when the grid is displayed the first time or bound again to a data source, and so your code has no effect (probably your case since you do not mention an exception).
Using form_shown is maybe a possible workaround, but I recommend you to use the DataGridView.DataBindingComplete event which is more especially designed to handle this situation.
See also these related issues (same cause):
Why DataGridColumn not getting removed from DataGridView
Datagirdview and tabcontrol issue
Strange issue with a datagridview and a tabcontrol C#
DataGridView has no columns

VB.NET web application - Update a data bound Listbox when underlying table / query changes

I have a page in my web application that contains two listboxes with buttons to move items back & forth between them. Each listbox is bound to a SQL query, the results of which change as the selected items are added or removed from the corresponding lists. This all works fine, except I cannot get the list boxes to update their contents on the fly, however if I refresh the web page, the contents update correctly.
Basically the user selects items in LeftListbox and clicks the Add button which calls code to loop through the LeftListbox and for each selected item adds a new record to a table (Score). The RightListbox should then update to show that the items have been added to the table.
Here is a snippet of code from the Click event of the Add button:
Dim i As Integer
For i = 0 To (LeftListbox.Items.Count() - 1)
If LeftListbox.Items(i).Selected Then
Try
DbUtils.StartTransaction()
Dim rec As ScoreRecord = New ScoreRecord
rec.Player_ID = CInt(Me.LeftListbox.Items(i).Value)
rec.Save()
DbUtils.CommitTransaction()
Catch ex As Exception
DbUtils.RollBackTransaction()
Me.Page.ErrorOnPage = True
Finally
DbUtils.EndTransaction()
End Try
End If
Next i
'** Here is where I want to refresh the list **
I've searched quite a bit for a solution, but I can't find anything that works so any help would be much appreciated.
Andrew
Use the same method (or code) used to populate the "right listbox" in the first place. The right ListBox's DataSource will be the same as it was prior to this code snipped being ran, so it must be updated since the underlying data has changed.

How to set default values for data bound controls for addition in VB.NET

I have a vb.net 2010 form with 22 data bound controls from two tables held in a dataset which is navigated by a bindingnavigator. This successfully adds deletes and updates. However what I need is when adding a new record I need some of the fields to be pre filled out. More specifically I have points balance fields etc which could be any value but will normally be 0 on a new customer so I want to initialise them to 0 when adding new records.
I located an AddingNew event on my datasource but this is called before the new item is added and thus all my initialisation is lost.
any help on this would be appreciated.
kind regards
Feldoh
Since you are using DataTables, you can manually set the DefaultValue property of the DataColumn:
Dim dt As New DataTable
Dim dc As New DataColumn("test", GetType(String))
dc.DefaultValue = "hello"
dt.Columns.Add(dc)
dt.Rows.Add()
Debug.WriteLine(dt.Rows(0)("test").ToString)
Result: hello
Answer including multiple linked tables solution:
Like LarsTech said using
dataset.table.Columns.Item("someField").DefaultValue = someValue
works nicely if you have a standard default but it also works for generated defaults, if you reset this default on saving to the next value you want if a new addition is made. However if you are using a dataset as your data source where a child table record cannot feasibly be generated (like in my case where an account id will be generated only on saving using a database trigger to link all different kinds of accounts) you can still set defaults for the other fields, the ones from the sibling (or non-existent parent) table but
dataset.siblingTable.Columns.Item("someField").DefaultValue = someValue
WILL NOT WORK as the binding navigator only generates the first sibling and the parent is not generated until the trigger. However on the BindingSource.PositionChanged event of the binding source that IS generated by clicking add you can freely put defaults into the actual controls on the screen and they will not be overwritten by nulls, clearly you need to restrict this so it only happens if the user pressed add by adding a variable to the Clicked event of the add button to tell you when add has been clicked and resetting this variable on save or roll-back. It is also possible to modify the bindings themselves which have an if null or empty default value.
Hope this helps someone else :)
Use the MouseUp event on the 'Add Row' button in the BindingNavigator instead of the "Click" event. This is becouse the new ROW does not exist in the datagridview until AFTER the click event is completed.
Private Sub BindingNavigatorAddNewItem_MouseUp(sender As Object, e As MouseEventArgs) Handles BindingNavigatorAddNewItem.MouseUp
'works with add row from the binding navigator
myDataGridView.Item(3, myDataGridView.CurrentRow.Index).Value = txtDefaultDescrip.Text.Trim
End Sub
to do this same thing when adding data directly in you DataGridView do this.
Private Sub myDataGridView_DefaultValuesNeeded(sender As Object, e As DataGridViewRowEventArgs) Handles myDataGridView.DefaultValuesNeeded
'works with add row inside a datagridview
e.Row.Cells(3).Value = txtDefaultDescrip.Text.Trim
End Sub
In this example I have a editable default value shown on my from. If you have a non-changing default value (e.g., is always 1 for column 3) then you should do that when setting up your datasource.