DataGridView column names not accessable after adding new column - vb.net

I'm trying to add a column to an existing data grid view and I'm getting an error after adding a column. Referencing the column by it's name throws a null reference exception and after some debugging I noticed, the names of the columns have disappeared after adding a column.
Before I add a new column you can see in the first image, that each column has a name. After I add a column, the second image shows the names of each column as being empty. No code was changed and the column being added to the data grid view was the only change.
DGV_List.Columns("Vendor").Visible = CB_Vendor.Checked
I've found one or two ways to get around this, such as directly referencing the column like Me.Vendor.Visible. But I'm curious why adding a new column could cause existing working code to fail.
Edit adding code
The code is really long so I'm linking it on pastebin. Also note the column was added manually and not with code. Nothing besides the form designer code changed when the error started.
Code that has null reference error after adding column
https://pastebin.com/inZCT27A
Form designer before adding column
https://pastebin.com/2nv33pA3
Form design after adding column
https://pastebin.com/7ULHpNwE

I am pretty sure that the problem lies in “WHEN” the CheckBoxs CheckedChanged event is fired.
If the check box is set to True in the designer, then, its CheckedChanged event will get fired "once" in the InitializeComponent method.
If the check box is set to False in the designer, then its CheckedChanged event will NOT be fired in the InitializeComponent method.
Because the check box is set to true in the designer, then "sometime" in the InitializeComponent method the CheckChanged event is going to get fired and when it does... you can NOT guarantee that the grid has been fully initialized.
Checking “anything” relating to the grid “before” it has been fully initialized is risky. This would easily explain some of the inconsistencies I and I am sure you have seen.
The main point would be that, because you DO want to reference the grid in the CheckChanged event of the check boxes, AND you DO want to have the check box initially checked, then you need to make sure the grid is fully initialized "before" you set the check box to True/False (checked/unchecked).
One way to do this is from the “designer”, UNCHECK the check boxes that reference the grid. This will prevent the CheckedChanged event from firing in the InitializeComponent method when the grid may not be fully initialized.
Then in the forms Load event, where we can pretty much guarantee the grid is initialized fully, set the check boxes state to checked. Then the CheckedChanged event can fire without errors. …
Private Sub MCRI_Checker_Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CB_Description.Checked = True
CB_Drawing.Checked = True
CB_FilePath.Checked = True
CB_Quantity.Checked = True
CB_ReqType.Checked = True
CB_Vendor.Checked = True
CB_WhereUsed.Checked = True
End Sub
I hope this helps and makes sense.

Related

Conditional visibility on MS Access Form - how to write in VBA or Macro

I have some very (very) basic MS Access knowledge. I'm trying to expand a bit into either VBA or macros as I'd like to put in some conditional visibility for my form. Basically, I have a checkbox. If it's checked, I want three or four more fields to pop up. Someone was able to point me to a basic VBA formula of if (this checkbox) = true then, (fieldx).visible = true, else, (fieldx).visibility = false, end if.
But I'm so new to this that I need more help and explanation. I tried putting it in but couldn't get it to work (no error message, just nothing changed at all).
Specific questions:
-Does this formula seem right?
-If I want multiple fields to be visible, can I combine them into one formula or should I create a new "if" statement for all?
-Where do I enter this code? I'm running the Office 365 version. For all I know, I'm not even putting it in the right place.
-How do I determine the field names to replace the (this checkbox) and (fieldx) in the formula? I tried entering the name I title the fields as, but with the spaces in the name I got an error message, and without the spaces nothing happened. Is there a specific naming convention to turn the field names into formula-appropriate titles? Is the name listed somewhere?
-Once I get the formula entered, is there something I have to do to get it to run/take effect? I tried saving, closing and reopening with no changes.
-Is this the best way to go about this?
If there's anything else you think I should know, I would love to hear it - but please keep in mind I'm very new to this so if you could keep it at "dummy" or ELI5 levels of explanation, I'd appreciate it!
after creating a form with 4 textboxes and a checkbox put the form in design mode (lower right corner has design mode selected, select a textbox and hit property sheet on the ribbon (or f4).
On the property sheet note the visible property. set the visible property to false. Now the textbox will be invisible when the form starts.
Tip you can select all the textboxes at the same time and set their properties all at once.
Every control on the form and even the various parts of the form have properties you can set and play with. For instance you can give any name you want to any control. On the property sheet go to the other tab and set the name property.
Tip: choose a name you you will remember without having to look it up and describes the controls function.
Next select the checkbox (not the checkbox's label). On the property sheet go to the event tab and select the on click event. hit the ellipsis and choose code builder. Access is Event Driven. We want the textboxes to appear when the checkbox is selected so we put that code in the checkbox click event.
after choosing code builder we get the code window where we can browse among all the events for all our forms. for now all you should see is something like:
Private Sub mycheckbox_Click()
End Sub
So insert some code to handle the checkboxes like:
Private Sub mycheckbox_Click()
If mycheckbox = True Then
txtbox1.Visible = True
txtbox2.Visible = True
txtbox3.Visible = True
txtbox4.Visible = True
Else
txtbox1.Visible = False
txtbox2.Visible = False
txtbox3.Visible = False
txtbox4.Visible = False
End If
End Sub
now when the checkbox is not checked no textboxes are visible.
but when the checkbox is checked they appear

Losing cell data when datagridview gets focus

I know I need to provide some code, but I'm not sure what I should show, so please suggest if you can.
I have a bound datagridview on a Windows form. After the form loads and the datagridview gains focus (on mouse click), the first row (and a specific column) loses it's data, changing the cell's state to dirty. It doesn't matter where I click to bring the dgv into focus, that row/column always goes blank. What event is firing that may trigger that loss of data?
Again, any suggestions as to what code to post would be great. I know that will help answer this question.
Edit #1
This code is an infinite loop, but I'm adding it in response to a comment:
Private Sub dgQCOrders_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles dgQCOrders.CellPainting
If e.RowIndex = 0 And e.ColumnIndex = 9 Then
If e.FormattedValue <> e.Value Then
MsgBox("Changed")
Else
MsgBox("Unchanged")
End If
End If
End Sub
Edit #2:
Private Sub dgQCOrders_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles dgQCOrders.CellPainting
If e.RowIndex = 0 And e.ColumnIndex = 9 Then
If e.FormattedValue <> e.Value Then
Me.txtTest.Text = "Changed"
Else
Me.txtTest.Text = "Unchanged"
End If
End If
End Sub
This test tells me that the new value is null, it is deleting that first record (which I already knew)--still don't know how to fix it!
Edit #3
More explanation:
Currently, the only event I'm handling is form_Load, which fills the dgv using the tableadapter for my (bound) dataset. I then bind the dgv to the binding source.
I know that this error only occurs when the dgv gains focus (I tested this by setting the focus to the dgv when the form loads). I have a series of checkboxes/listboxes/textboxes on this form as well that allows the user to filter the dgv dynamically (back-end, I filter the binding source). If I filter the dgv first, the same row and the same column (their indexes do not change) maintains it's value when I move the focus to the dgv. When I clear the filter, the same row and the same column, loses it's data again.
I did have the _CellStateChanged event firing after a user makes an edit. Currently, it is commented out so the data loss isn't reflected in my dataset.
Additionally, I have another dgv on a different form, bound the exact same way, with the _CellStateChanged event and everything fires and saves correctly. I have gone through the designer coding for both forms, I can't find any setting difference between the two.
I'm losing my mind over here! Any help is GREATLY appreciated!
I decided to recreate the form from scratch and this error is no longer occuring. I have compared the two sets of code and can't find one discrepancy between them. If anyone has this problem in the future, save time and recreate all of the objects related to your dgv.
Maybe I understand that statement within the focus cell is not saved in the database table if U save
this problem I solved
add blank textbox control to your form which contain dgv and named txtFocus
placed it behand dgv and use its properties send to back Or
Evoked by the bottom of the screen so do not show it
then
before save
white then :
txtFocus.Focus()
sendKeys.send("{F2}")
only in this case U can save the data inside last cell changed in dgv
best Reg
Ashraf

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.

WinForms binding

I have some controls bound to a BindingSource control.
I want to do a calculation when the value changes in one control and set the result on another control.
Do I update the textbox the property is bound to or do I update the underlying entity which would update the control anyway (I hope)?
When I change combobox A (OnPropertyChange) textbox B is updated with the new calculated result. This works fine, but I have noticed that when I leave combobox A it reverts back to its original value. What is going on here!
Private Sub ComboBoxEditCostCode_EditValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBoxEditCostCode.EditValueChanged
Select Case ComboBoxEditCostCode.EditValue
Case "7"
CType(TransactionEntityBindingSource.Current, TblTransactionsEntity).Qbdescription = "7-is here"
Case "2"
CType(TransactionEntityBindingSource.Current, TblTransactionsEntity).Qbdescription = "2-is here"
Case Else
CType(TransactionEntityBindingSource.Current, TblTransactionsEntity).Qbdescription = "7-is here"
End Select
End Sub
if we bind a control to a source, then if the source changes, we can make the its value automatically reflected in the control. About the problem you are facing, it would be better if you show the code snippet.
Tell more about your changing, how second text box is bound?
You have to change your initial data instead of changing textbox b value.
Also when textbox A loses it focus raises EndEdit event and I think binding mechanism refreshes value in textbox B.
You can control on which action editing is done when you setting your binding to textboxes.
as a rule of thumb, if you are using a binding source you always CRUD the data through it. Don't forget to call BindingSource.EndEdit when you are done, hope this helps

Reading 'Checked' Property Of Dynamic CheckBox on Page Postback

Apologies in advance for the long-winded post, but I'm having some trouble with a .NET page I'm building.
END QUESTION: How can I check the 'Checked' property of a dynamically-created checkbox during the Page_Load subroutine?
DETAILS: Basically, I have a VB.NET page that creates some table rows dynamically, based on a number selected by the user. So, for example, if the user selects "3" from a dropdown list, the page posts back and creates three table rows. Each row contains a couple of textboxes, a dropdown list, and a checkbox (which are all .NET form controls rather than plain HTML controls, I should point out).
Typically, the user would enter a few details into the form controls, and click the 'Submit' button, after which the page iterates through each row, and inserts the data into a SQL Server table.
But if the user ticks the checkbox for that row, this signifies that the page is to ignore that row, and NOT insert that row of data into the database when the user clicks 'Submit'.
This works well, but there is a problem. If the user clicks 'Submit' and some of the values entered into the form controls are invalid (so, for example, the user didn't enter their name) then the page won't submit the data, and instead, shows an error to the user informing them of the values they need to change. But if the user creates three rows, for example, but decides to "ignore" the third row (by ticking the checkbox) then when the page posts back, finds some invalid entries, and re-shows the form to the user to allow them to correct any errors, I'd rather the page didn't render the third row altogether. After all, they chose to create three rows originally, but then decided that they only needed two. So it makes sense that the third row is not recreated.
To start with, I simply used code similar to the following within my Page_Load subroutine:
If objCheckbox.Checked = False
' Render the row, and recreate the dynamic controls '
Else
' Dont render the row or any of the controls '
End If
But what seemed to happen was that objCheckbox.Checked was always returning False, even when the checkbox was ticked. Once the page had loaded, the table rows had rendered again, and the tick was present in the checkbox, so it's not like the value was lost on postback. But at the point I check whether the checkbox is ticked, it always returns False, rendering a table row that the user doesn't need.
Does anyone know how to get round this problem? I've read lots of articles about the .NET ViewState, and the page lifecycle, but I've yet to find a solution that works. I simply need to be able to check if a checkbox is ticked before re-creating some dynamic controls.
I tried this alternative code, which utilises the ViewState, but to no avail:
If objIgnoreCheckbox.ViewState("Checked") = False Then
' Render the row, and recreate the dynamic controls '
Else
' Dont render the row or any of the controls '
End If
When doing this, I get the following error:
'System.Web.UI.Control.Protected Overridable ReadOnly Property ViewState() As System.Web.UI.StateBag' is not accessible in this context because it is 'Protected'.
So I tried to create a custom class, that inherited from Checkbox, and tried to override the ViewState property to make it public, so that it can be read from:
Public Class CheckboxControl
' Inherits all Checkbox properties and methods '
Inherits Checkbox
' Create the public ViewState property '
Public Overrides ReadOnly Property ViewState As StateBag
Get
Dim objChecked As Object = ViewState("Checked")
If Not (IsNothing(objChecked)) Then
Return objChecked
End If
End Get
End Property
End Class
But then I basically found out that you can't override a protected member with a public one. I've had very little experience with creating new classes etc, so I'm stumped.
So if anyone can tell me how to go about checking the darned checkbox, I'd be eternally grateful! I've spent a full working day trying to solve the problem, but with no luck!
Thanks in advance!
For static controls, the view state of controls is restored in Page_Init, which happens before Page_Load, so they contain the correct values in Page_Load. Dynamic controls are created in Page_Load, so their viewstate is incorrect in Page_Load and will be restored after Page_Load, but before calling event handlers. MSDN says:
After the Page_Load event has run, but before control event-handling methods are called, the remaining view state information is loaded into the dynamically created controls.
This is why Checked returns false, and why changing the visibility of CheckBox.ViewState will not solve your problem.
Solution (untested, but I think it should work): Create all controls (even those that you don't want to display) in Page_Load. Attach an event handler on CheckedChanged to your CheckBoxes (in Page_Load). After Page_Load has finished, ASP.NET will restore the view state of the newly created controls (that's why it is important to create the same controls in Page_Load, so that ASP.NET can correctly map the view state to the control), and ASP.NET will call your event handler for those CheckBoxes that have been changed. There, you can remove the rows you don't want to display.
This is how you add the event handler
AddHandler objCheckbox.CheckedChanged, AddressOf MyCheckedChangedFunction
This function would look something like this:
Function MyCheckedChangedFunction(sender As Object, e As EventArgs)
Dim objCheckbox = DirectCast(sender, CheckBox)
... access objCheckbox.Changed and do something useful here ...
End Function