0

Does Vb.net have a quick way to disable all editable fields (textboxes, checkboxes,...) in a form? I'm trying to protect data from "accidentally" being overwritten. My user has to click an edit button to "unlock" the fields and make them editable and the user must press the save button to update the database and lock the fields once more.

So far i've only found a manual input to make every textbox and checkbox (about 30 of them in different tabs of the form) readonly values to true and disable them if i click on my edit button. Any advice on how to do this? can i do a "for each" in a quicker way? how would i formulate the code? i found a 2007 article with this snippet:

For Each control As Control In Me.Controls

If TypeOf (control) Is TextBox Then

CType(control, TextBox).ReadOnly = True

End If
Next

but i'd need all types of field in one go.

thanks for any advice on this subject. I'm a beginner.

Izzy
  • 29
  • 7
  • If they're all in a panel/groupbox or similar, you can disable the panel – Caius Jard Sep 29 '20 at 09:30
  • @CaiusJard: they're in a tabcontrol due to the big amount of editing fields, 5 tabs with each 2 tabs of around 5 texfields – Izzy Sep 30 '20 at 18:31
  • Probably go for a solution like I posted then, where it will recursively look through all controls whether they're inside a panel/sub panel etc or not. If you have textboxes outside the tab control that you don't want getting caught up in the process you can start searching for controls by saying `yourTabControl.GetAllChildren` rather than starting searching in the form. Don't forget that once you have used getallchildren to build a list you can further manually add to or remove from the list if you have custom considerations. All you need to get to is a list of all your textboxes to turn off – Caius Jard Sep 30 '20 at 19:05

4 Answers4

2

With reference to this question

If you put this in a module called ControlExt.vb:

Imports System.Runtime.CompilerServices
Module ControlExt

<Extension()>
Public Function GetAllChildren(Of T As Control)(parentControl As Control) As IEnumerable(Of T)
    Dim controls = parentControl.Controls.Cast(Of Control)
    Return controls.SelectMany(Of Control)(Function(ctrl) _
        GetAllChildren(Of T)(ctrl)) _
        .Concat(controls) _
        .Where(Function(ctrl) ctrl.GetType() = GetType(T)) _
    .Cast(Of T)
End Function

End Module

Then you could do this in your class:



Class WhateverForm

  Private _allTextboxes as List(Of TextBox)

  Public Sub New() 'in the constructor

    InitializeComponent()

    _allTextboxes = Me.GetAllChildren(Of TextBox).ToList()
  End Sub

Which means all the textboxes on your form, wherever they are (inside whatever subpanels of subpanels, of tabpages of groupboxes etc), are now in a List.. And you can do this in your edit button click handler:

_allTextboxes.ForEach(Sub(b) b.ReadOnly = False)

And of course, perform the corollary ReadOnly = True in the Save button. You don't have to limit it to textboxes; GetAllChildren can find anything - maybe you want to lock the checkboxes too - have another list of _allCheckboxes, GetAllChildren(Of CheckBox) and in the ForEach set Enabled = etc

I'd point out that ReadOnly and Enabled are slightly different and as a UX pointer if you're going to make stuff greyed out in a UI (or "half greyed out" in the case of ReadOnly), then you should have something explaining why the option is greyed out/how to enable it. It won't be immediately obvious to users that they have to click Enable and if you don't want tech support calls going "I'm clicking in the name box and I can see the cursor flashing but when i type nothing happens!" then give them a nudge with "View mode: To enable editing of this data, click [EDIT]" etc

Caius Jard
  • 72,509
  • 5
  • 49
  • 80
1

This will disable every TextBox and every CheckBox that was added directly to a TabPage in TabControl1:

For each tp As TabPage In TabControl1.TabPages
    For Each tb In tp.Controls.OfType(Of TextBox)()
        tb.Enabled = False
    Next

    For Each cb In tp.Controls.OfType(Of CheckBox)()
        cb.Enabled = False
    Next
Next
jmcilhinney
  • 50,448
  • 5
  • 26
  • 46
0

Try this:

For Each control As Control In Me.Controls
  Try 
    CType(control, TypeOf(control)).ReadOnly = True
  Catch 
    ' Do nothing
  End Try
Next
Wasif
  • 14,755
  • 3
  • 14
  • 34
  • 1
    Note; doesn't recurse into panels. Also not really sure what you're aiming to do with `CType(control, TypeOf(control))` performing a runtime determination of the type of the control isn't going to help the design time compilation process work out whether it has a ReadOnly property or not, so that ain't gonna work.. – Caius Jard Sep 29 '20 at 09:30
0

Thanks for the GetAllChildren function. Thought I'd share a continuation of it so you can lock all common controls based on a tag.

Public Sub LockControls(ByVal frm_Form As Form,
                        ByVal bln_Lock As Boolean,
                        ByVal str_TAG As String)

    Dim allTextboxes As List(Of TextBox)
    Dim allComboBoxes As List(Of ComboBox)
    Dim allDateTimePickers As List(Of DateTimePicker)
    Dim allDataGrids As List(Of DataGridView)
    Dim allCheckBoxes As List(Of CheckBox)
    Dim allListBoxes As List(Of ListBox)
    Dim allButtons As List(Of Button)

    Dim blnEnable As Boolean
    Dim blnReadonly As Boolean

    If bln_Lock Then ' we need to lock controls
        blnEnable = False
        blnReadonly = True
    Else
        blnEnable = True
        blnReadonly = False
    End If

    allTextboxes = frm_Form.GetAllChildren(Of TextBox).ToList
    For Each CTL In allTextboxes
        If ContainsTag(CTL.Tag, str_TAG) Then
            CTL.ReadOnly = blnReadonly
        End If
    Next

    allComboBoxes = frm_Form.GetAllChildren(Of ComboBox).ToList
    For Each CTL In allComboBoxes
        If ContainsTag(CTL.Tag, str_TAG) Then
            CTL.Enabled = blnEnable
        End If
    Next

    allCheckBoxes = frm_Form.GetAllChildren(Of CheckBox).ToList
    For Each CTL In allCheckBoxes
        If ContainsTag(CTL.Tag, str_TAG) Then
            CTL.Enabled = blnEnable
        End If
    Next

    allButtons = frm_Form.GetAllChildren(Of Button).ToList
    For Each CTL In allButtons
        If ContainsTag(CTL.Tag, str_TAG) Then
            CTL.Enabled = blnEnable
        End If
    Next

    allDateTimePickers = frm_Form.GetAllChildren(Of DateTimePicker).ToList
    For Each CTL In allDateTimePickers
        If ContainsTag(CTL.Tag, str_TAG) Then
            CTL.Enabled = blnEnable
        End If
    Next

    allDataGrids = frm_Form.GetAllChildren(Of DataGridView).ToList
    For Each CTL In allDataGrids
        If ContainsTag(CTL.Tag, str_TAG) Then
            CTL.ReadOnly = blnReadonly
        End If
    Next

    allListBoxes = frm_Form.GetAllChildren(Of ListBox).ToList
    For Each CTL In allListBoxes
        If ContainsTag(CTL.Tag, str_TAG) Then
            CTL.Enabled = blnEnable
        End If
    Next

End Sub

Private Function ContainsTag(fulltag As String, searchTag As String) As Boolean
    Dim found As Boolean
    Dim tags As String() = Nz(fulltag, "").Split(New Char() {","c})

    For Each tag In tags
        If tag = searchTag Then
            found = True
        End If
    Next

    Return found
End Function

Public Function Nz(ByVal Value As Object, Optional ByVal DefaultVal As Object = "") As Object
    If Value Is Nothing OrElse IsDBNull(Value) Then
        Return DefaultVal
    Else
        Return Value
    End If
End Function