debugging shows that all items in checkbox list as unchecked when there are 3checked - vb.net

so im dynamically populating a checkbox list. I have confirmed that my text and values are correct for each checkbox but when I check a few and click my event button when I loop through the items they are all set to select=false...
Dim resource As ListItem
Dim SelectedHashTable As New Hashtable
For Each resource In chkResources.Items
If resource.Selected = True Then
SelectedHashTable.Add(resource.Text, resource.Value)
End If
Next
set checkpoint at line 5 to view contents of hash table but it is never triggered. Even when I check all boxes. Anyone any idea?

Where are you dynamically populating the checkboxlist? If it's any time after the OnInit event, then the control's viewstate is not getting saved properly and your selections will be overridden on every postback. Try dynamically populating your list in the OnInit handler.

Related

Datagridview menuitem - get data of datagridview row

I am using a Datagridview, and if I right click on a row in the Datagridview I am catching the Datagridview MouseClick handler. Inside this handler I create a menuItem, if I click one entry in this menuItem I want to execute some code, and this code should get some data from the row I have selected in the Datagridview. How can I do this?
I am using this kind of code to create menuItem entrys:
Dim firefox As New MenuItem("Firefox", AddressOf contextMenu_ItemClicked)
firefox.Tag = "firefox"
Another question, do I need to add this tag, or am I also able to read out the name of the menuitem in the contextMenu_ItemClicked function?
Thanks!

Make a button have multiple uses

okay... How do I explain this without being totally confusing?... Alright, I have this form that has MenuScripts (top-levels and second-levels). The problem that I am having is one of the second-levels is "Add" which brings you to another form when clicked. This other form has a button ("Record") and text boxes. This other form allows the user to input data and when the record button is clicked, the inputted data is written into a text file. Ok, so back to the first form. Another second-level MenuScript is "Update" which also brings the user to the other form; but first, the user has to click an item within a listbox to proceed. How do I get the data from the selected item to appear in the appropriate textboxes and how do I get the record button to update data instead of being confused and thinking it is only a add-data button?
Is there a way to use an "if" statement to say something like "if mnuAdd is clicked then" "elseif mnuUpdate is clicked then". Would something like that work for giving the record button multiple uses?
Also, if someone can give me some pointers on making sure the user selects an item within the listbox would definitely be a plus! Thanks, guys!
Unfortunately, I cannot add images since my reputation is too low.
Here is a visual representation of my ultimate goal
Easiest way: before displaying the second form set it's Tag property to something distinct – say "Add" or "Update" – depending on which menu item is selected. Then you just test the Tag value in the button's Click event and proceed accordingly.
As for determining whether a list item is selected: well if there isn't the ListBox's SelectedIndex property will be set to -1.
You need to put a public property on the second form (Details) which specifies which mode it is in. For instance, you could create a mode enumeration like this:
Public Enum EntryModes
AddBook
UpdateBook
End Enum
Then, define a public mode property on the second form, like this:
Public Property EntryMode As EntryModes
Get
Return _entryMode
End Get
Set(ByVal value As EntryMode)
_entryMode = value
End Set
End Property
Private _entryMode As EntryMode
Then, when you show the second form from the menu, just set the property first, before showing it:
Private Sub mnuAdd_Click(sender As Object, e As EventArgs)
Dim dialog As New DetailsDialog()
dialog.EntryMode = EntryModes.AddBook
dialog.ShowDialog()
End Sub
Private Sub mnuUpdate_Click(sender As Object, e As EventArgs)
Dim dialog As New DetailsDialog()
dialog.EntryMode = EntryModes.UpdateBook
dialog.BookToUpdate = ListBox1.SelectedItem
dialog.ShowDialog()
End Sub
As you can see, in the Upate menu click, I also added a line that passes the information for which book should be updated.

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.

Referencing cell values on DataGridView from another form

This is bugging me. I have a "main" form named frmMain with a DataGridView object named objDataGrid.
When a user double clicks on a row or clicks another button, I hide the main form, open a new form and want to reference the values in the row selected by the user but I keep getting an error when I try to access some, but not all, of the datagridview's properties.
For example here is the code that opens the form:
On Error Resume Next
Me.Hide()
frmGenerate.Show()
In the frmGenerate's load event I do the following:
Dim frmMain As frmMain = Nothing
frmMain = New frmMain
Any time I try to grab a value from the grid I get various errors.
frmMain.objDataGrid.Item(1, 2).Value
frmMain.objDataGrid.Rows(2).Cells(4).Value
frmMain.objDataGrid.SelectedRows(0).Index
frmMain.objDataGrid.Item(1, frmMain.objDataGrid.SelectedRows(0).Index).Value
These return index out of range errors even though I know for sure the indexes are correct.
Any ideas?
Thanks.
Why are you creating a new instance of frmMain? You need to refer to the existing one where they've selected a row.
You could pass just the row of the datagrid or PK field values instead of referencing the other form.

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