Disabling checkbox selections in VB .NET 2008 Winform Listview - vb.net

How do you disable additional checkbox selections/deselections without sacrificing the functionality of the ListView? I know you can call: ListView.Enabled = False, but that also disables any scrolling within it.
For example: I have a timer that starts a backup based on the Listview items that are checked. After a certain time, I don't want the end-user to be able to click on any of the checkboxes within the listview (so I have a set number of items to backup), but I do want them to be able to scroll the list while the backup is being performed. I tried this:
Private Sub clboxOptions_ItemChecked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ItemCheckedEventArgs) Handles clboxOptions.ItemChecked
If backupStarted = True Then
If e.Item.Checked = True Then
e.Item.Checked = False
Else
e.Item.Checked = True
End If
But this doesn't seem to work for me.
Thanks!
JFV

Here is an other method to disable the users click on listviewitem checkbox.
Public Sub ChangeItemCheckState(ByVal val As Boolean, ByVal index As Integer)
If Monitor.TryEnter(Me.Items(index), 10) Then
Try
Me.Items(index).Checked = val
Finally
Monitor.Exit(Me.Items(index))
End Try
End If
End Sub
Public Sub ChangeItemCheckState(ByVal val As Boolean, ByVal item As ListViewItem)
If Monitor.TryEnter(item, 10) Then
Try
item.Checked = val
Finally
Monitor.Exit(item)
End Try
End If
End Sub
Private Sub ListviewOPC_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles Me.ItemCheck
If Monitor.IsEntered(Me.Items(e.Index)) Then
'
Else
'prevent click from users
e.NewValue = e.CurrentValue
End If
End Sub
this method is thread safe. To change the checkedstate of an item you have to call the ChangeItemCheckState methods. If you want to enable/disable the itemcheck by click, you have to add another property.
Private disableUserCheckItem As Boolean
Public Property PreventUserCheckItem() As Boolean
Get
Return disableUserCheckItem
End Get
Set(ByVal value As Boolean)
disableUserCheckItem = value
End Set
End Property
Public Sub ChangeItemCheckState(ByVal val As Boolean, ByVal index As Integer)
If Monitor.TryEnter(Me.Items(index), 10) Then
Try
Me.Items(index).Checked = val
Finally
Monitor.Exit(Me.Items(index))
End Try
End If
End Sub
Public Sub ChangeItemCheckState(ByVal val As Boolean, ByVal item As ListViewItem)
If Monitor.TryEnter(item, 10) Then
Try
item.Checked = val
Finally
Monitor.Exit(item)
End Try
End If
End Sub
Private Sub ListviewOPC_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles Me.ItemCheck
If Monitor.IsEntered(Me.Items(e.Index)) Then
'do nothing or other nessesary things.
Else
'prevent click from users
If PreventUserCheckItem Then
e.NewValue = e.CurrentValue
End If
End If
End Sub

Instead using the built-in CheckBoxes property, you could draw the check boxes yourself.
Google around and find an example of an OwnerDraw ListView. Draw the checkboxes yourself. Add a new property to your ListView (something like ReadOnly). When ReadOnly is true, draw the checkboxes as disabled and ignore the click messages.

You could use ObjectListView (which is a wrapper around a normal .NET ListView). It provides a callback, CheckStatePutter, which is called when the user clicks on a checkbox. In that callback, you can decide whether or not to accept the new checkbox value.
This is a recipe describing this process: How do I use checkboxes in my ObjectListView?

I found out what my issue was. I was using the 'ItemChecked' instead of the 'ItemCheck' Method. The below code works for me:
Private Sub clboxOptions_ItemCheck(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ItemCheckEventArgs) Handles clboxOptions.ItemCheck
Try
If backupStarted = True Then
If e.CurrentValue <> e.NewValue Then
e.NewValue = e.CurrentValue
Else
e.NewValue = e.NewValue
End If
End If
End Sub

I want disable CheckBox in Listview. When I click Button Go. I was using the 'ItemChecked' Method. I use code this:
Public Sub CheckBoxChecked(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckedEventArgs)
Try
If bCheckFromEvent Then
bCheckFromEvent = False
Return
End If
If BrunService Then
bCheckFromEvent = True
ListView.Items(e.Item.Index).Checked = Not ListView.Items(e.Item.Index).Checked
End If
Catch ex As Exception
MsgBox("CheckBoxChecked: " & ex.Message, MsgBoxStyle.Critical Or MsgBoxStyle.OkOnly, "ERROR")
End Try
End Sub

Related

VB.NET: Add\remove row indexes of datagridview checkboxes rows

I am working with forms in VB.NET
There is a DatagridView table with a checkbox column.
See the picture below:
I am interested in the question: how to add the line index to the list when clicking in the checkbox (when we activate the checked status), and remove it from the list when we uncheck the checkbox?
Tried the following but this is not the correct solution:
If e.ColumnIndex = chk_column.Index Then
If e.RowIndex >= 0 Then
Try
For Each row As DataGridViewRow In dataGridNames.Rows
Dim cell As DataGridViewCheckBoxCell = TryCast(row.Cells(5), DataGridViewCheckBoxCell)
If cell.Value Is cell.FalseValue Then
bList_indexes.Add(DataGridnames.CurrentCell.RowIndex)
Exit For
Else 'If cell.Value Is cell.TrueValue Then
bList_indexes.RemoveAt(DataGridnames.CurrentCell.RowIndex)
End If
Next
Catch ex As Exception
'Show the exception's message.
'MessageBox.Show(ex.Message)
'Throw New Exception("Something happened.")
End try
End If
End If
Using DataSources allows you to take the logic out of mucking around in DataGridView events. You shouldn't perform [much] business logic on the UI anyways.
Here is the class I used to represent your data.
Public Class ClassWithSelect
Public Property [Select] As Boolean
Public Property Name As String
Public Sub New(s As Boolean, n As String)
Me.Select = s
Me.Name = n
End Sub
End Class
And all the code to set DataSources
Private myDataSource As List(Of ClassWithSelect)
Private selectedIndices As List(Of Integer)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
myDataSource = Enumerable.Range(65, 10).Select(Function(i) New ClassWithSelect(False, Chr(i).ToString())).ToList()
DataGridView1.DataSource = myDataSource
updateSelectedIndices()
End Sub
Private Sub DataGridView1_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
updateSelectedIndices()
End Sub
Private Sub DataGridView1_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
End Sub
Private Sub updateSelectedIndices()
selectedIndices = New List(Of Integer)()
For i = 0 To myDataSource.Count - 1
If myDataSource(i).Select Then selectedIndices.Add(i)
Next
ListBox1.DataSource = selectedIndices
End Sub
And the end result
Now you don't need to access the UI to get the indices for further processing as they are in the class-level variable selectedIndices. The UI is meant for user I/O, NOT for storing state.
Note: The event handler was taken from this answer but this answer is also linked as an improvement to the check change handler, but I felt the complexity would distract from my answer. If you find you need to click fast, look into the latter.
Also Note: The method updateSelectedIndices() should have inside it an InvokeRequired check if you plan to perform work off the UI thread

How do I code out with numeric keypads with multi textboxes?

I'm trying to code out a programme where the user sees a form and in that form, there are 2 text boxes and 10 buttons.
Username:
Password:
1 2 3
4 5 6
7 8 9
0
I've tried this code
Private Sub Btn1_Click(sender As Object, e As EventArgs) Handles Btn1.Click
If UsernameTextbox.Focused = True Then
UsernameTextbox.Text = UsernameTextbox.Text + "1"
End If
End Sub
I understand that clicking on Btn1 will steal the focus from the text box. So how can I write the programme?
One option would be to declare a variable of type Control and, in the Leave event handler for each control, assign the sender to that variable. You can then use that variable in the Click event handler of your Button to determine which control had focus and possibly reassign back to that control and then update it appropriately. You can do the lot with two event handlers, e.g.
Private previouslyActiveTextBox As TextBox
Private Sub TextBoxes_Leave(sender As Object, e As EventArgs) Handles TextBox2.Leave,
TextBox1.Leave
previouslyActiveTextBox = DirectCast(sender, TextBox)
End Sub
Private Sub Buttons_Click(sender As Object, e As EventArgs) Handles Button3.Click,
Button2.Click,
Button1.Click
previouslyActiveTextBox.Select()
previouslyActiveTextBox.SelectedText = CStr(DirectCast(sender, Button).Tag)
End Sub
That code handles multiple events with a single method in both cases. It also requires that you assign the number for each Button to the Tag property of that control. Note that it also sets the SelectedText, rather than appending to the Text property. That is more correct because it will add the new text where the caret is actually located and replace text if it is selected.
An even better option might be to use a custom button control that doesn't take focus. Here's one I prepared earlier:
http://www.vbforums.com/showthread.php?459890-Building-Blocks-for-an-On-screen-Keyboard
Items within a ToolStrip do not grab focus when clicked. While the standard ToolStrip usage is as a menu bar, there is nothing that prevents you from using it as a container for buttons laid out in a grid. In fact, the class ToolStrip.LayoutStyle Property allows you select a table style.
The following is a proof-of-concept custom ToolStrip that is prepopulated with the buttons to create a number pad like control. The control has sufficient function to work as intended, but is not locked down to prevent misuse by manipulating the Items collection and other properties.
Public Class NumPadToolstrip : Inherits ToolStrip
Private _ButtonSize As Size = New Size(50, 50)
Private _ButtonMargin As Padding = New Padding(5)
Private _ButtonBackColor As Color = Color.Ivory
Public Sub New()
MyBase.New
LayoutStyle = ToolStripLayoutStyle.Table
Dim settings As TableLayoutSettings = CType(LayoutSettings, TableLayoutSettings)
settings.ColumnCount = 3
settings.RowCount = 4
AddButtons(7, 9)
AddButtons(4, 6)
AddButtons(1, 3)
AddButtons(0, 0)
Dock = DockStyle.None
AutoSize = True
BackColor = Color.LightGray
End Sub
Public Property ButtonSize As Size
Get
Return _ButtonSize
End Get
Set(value As Size)
If value <> _ButtonSize Then
_ButtonSize = value
UpdateButtonSizes()
End If
End Set
End Property
Public Property ButtonMargin As Padding
Get
Return _ButtonMargin
End Get
Set(value As Padding)
If value <> _ButtonMargin Then
_ButtonMargin = value
UpdateMargins()
End If
End Set
End Property
Public Property ButtonBackColor As Color
Get
Return _ButtonBackColor
End Get
Set(value As Color)
If value <> _ButtonBackColor Then
_ButtonBackColor = value
UpdateButtonBackColor()
End If
End Set
End Property
Private Sub AddButtons(start As Int32, [end] As Int32)
For num As Int32 = start To [end]
Dim b As New ToolStripButton With {.Text = num.ToString(),
.Size = ButtonSize,
.Margin = ButtonMargin,
.BackColor = ButtonBackColor,
.AutoSize = False}
AddHandler b.Paint, Sub(sender As Object, e As PaintEventArgs)
With e.Graphics
Dim r As Rectangle = e.ClipRectangle
r.Inflate(-1, -1)
r.Location = Point.Empty
.DrawRectangle(Pens.Black, r)
End With
End Sub
Items.Add(b)
Next
End Sub
Private Sub UpdateButtonSizes()
SuspendLayout()
For Each btn As ToolStripButton In Items.OfType(Of ToolStripButton)
btn.Size = _ButtonSize
Next
ResumeLayout()
End Sub
Private Sub UpdateMargins()
SuspendLayout()
For Each btn As ToolStripButton In Items.OfType(Of ToolStripButton)
btn.Margin = _ButtonMargin
Next
ResumeLayout()
End Sub
Private Sub UpdateButtonBackColor()
SuspendLayout()
For Each btn As ToolStripButton In Items.OfType(Of ToolStripButton)
btn.BackColor = _ButtonBackColor
Next
ResumeLayout()
End Sub
End Class
Add the above class to your project and perform a build operation. The NumPadToolstrip control should then be available in the ToolBox. Add the control to the form and then add a handler for its ItemClicked event to pass the proper text to the TextBox.
Private Sub NumPadToolstrip1_ItemClicked(sender As Object, e As ToolStripItemClickedEventArgs) Handles NumPadToolstrip1.ItemClicked
Dim tb As TextBoxBase = TryCast(ActiveControl, TextBoxBase)
If tb IsNot Nothing Then tb.SelectedText = e.ClickedItem.Text
End Sub

Highlight scroll bar of textbox [duplicate]

Is it possible to show/hide the scroll bar in a text box only when the line count in the text box is more than the number of lines displayed?
Consider using the RichTextBox -- it has that behavior built in.
Thanks dummy, it works! Here short version of dummy answer in c#
Call this code at the end of your SizeChanged and TextChanged handlers:
Size textBoxRect = TextRenderer.MeasureText(
this.YourTextBox.Text,
this.YourTextBox.Font,
new Size(this.YourTextBox.Width, int.MaxValue),
TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl);
try
{
this.YourTextBox.ScrollBars = textBoxRect.Height > this.YourTextBox.Height ?
ScrollBars.Vertical :
ScrollBars.None;
} catch (System.ComponentModel.Win32Exception)
{
// this sometimes throws a "failure to create window handle" error.
// This might happen if the TextBox is unvisible and/or
// too small to display a toolbar.
}
Public Class TextBoxScrollbarPlugin
Private WithEvents mTarget As TextBox
''' <summary>
''' After the Handle is created, mTarget.IsHandleCreated always returns
''' TRUE, even after HandleDestroyed is fired.
''' </summary>
''' <remarks></remarks>
Private mIsHandleCreated As Boolean = False
Public Sub New(item As TextBox)
mTarget = item
mIsHandleCreated = mTarget.IsHandleCreated
End Sub
Private Sub Update()
If Not mTarget.IsHandleCreated Then
Return
ElseIf Not mIsHandleCreated Then
Return
End If
Dim textBoxRect = TextRenderer.MeasureText(mTarget.Text,
mTarget.Font,
New Size(mTarget.Width, Integer.MaxValue),
TextFormatFlags.WordBreak + TextFormatFlags.TextBoxControl)
Try
If textBoxRect.Height > mTarget.Height Then
mTarget.ScrollBars = ScrollBars.Vertical
Else
mTarget.ScrollBars = ScrollBars.None
End If
Catch ex As System.ComponentModel.Win32Exception
'this sometimes throws a "failure to create window handle"
'error.
'This might happen if the TextBox is unvisible and/or
'to small to display a toolbar.
If mLog.IsWarnEnabled Then mLog.Warn("Update()", ex)
End Try
End Sub
Private Sub mTarget_HandleCreated(sender As Object, e As System.EventArgs) Handles mTarget.HandleCreated
mIsHandleCreated = True
End Sub
Private Sub mTarget_HandleDestroyed(sender As Object, e As System.EventArgs) Handles mTarget.HandleDestroyed
mIsHandleCreated = False
End Sub
Private Sub mTarget_SizeChanged(sender As Object, e As System.EventArgs) Handles mTarget.SizeChanged
Update()
End Sub
Private Sub mTarget_TextChanged(sender As Object, e As System.EventArgs) Handles mTarget.TextChanged
Update()
End Sub
End Class
Private mPlugins As New List(Of Object)
Private Sub Form_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
mPlugins.Add(New TextBoxScrollbarPlugin(txtBoxOne))
mPlugins.Add(New TextBoxScrollbarPlugin(txtBoxTwo))
mPlugins.Add(New TextBoxScrollbarPlugin(txtBoxThree))
End Sub
I've got tnimas solution working in vb. Functions quite well as written and I've not seen the errors.
Private Sub TextBoxSizeChanged(sender As Object, e As EventArgs) Handles Me.SizeChanged
Dim textBoxRect As Size = TextRenderer.MeasureText(TextBox.Text, TextBox.Font, New Size(TextBox.Width, Integer.MaxValue), TextFormatFlags.WordBreak Or TextFormatFlags.TextBoxControl)
Try
TextBox.ScrollBar = If(textBoxRect.Height > TextBox.Height, ScrollBars.Vertical, ScrollBars.None)
Catch ex As Exception
'handle error
End Try
End Sub
I myself tried tnimas' solution but unable to catch the exception, so I use the WinApi to toggle the visible state of scrollbars instead like so:
Size textBoxRect = TextRenderer.MeasureText(YourTextBox.Text, YourTextBox.Font, new Size(YourTextBox.Width, int.MaxValue), TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl);
WinApi.ShowScrollBar(YourTextBox.Handle, (int)WinApi.ScrollBar.SB_VERT, textBoxRect.Height > YourTextBox.Height ? true : false);
This method does not cause the exception, though should note that hiding scrollbars like this will disable scroll messages, but this is fine if you're just hiding the scrollbars for when the text area can't be scrolled anyway.

Button of UserControl vanishes when program is debugged

My UserControl button disappears when I debug my program. I have checked the code including the designer.vb code countless times there's nothing that makes the button .enabled = false or .visible = false. Any ideas why this is happening?
On my UserControl:
Private Sub btn_Begin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Begin.Click
Start_Race()
End Sub
Public Sub Start_Race()
TimeNow(Past_Time)
TimeNow(Start_Time)
lbl_Start_Time_Driver.Text = Past_Time
btn_Begin.BackColor = Color.Green
btn_Begin.Text = "Started!"
End Sub
Public Property Active_bool As Boolean
Get
Return btn_Begin.Visible
End Get
Set(ByVal value As Boolean)
btn_Begin.Visible = value
End Set
End Property
On Form1:
Private Sub btn_Start_All_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Start_All.Click
Dim allActiveUserControls = From uc_Index In Controls.OfType(Of LapTimerGUI)()
Where uc_Index.Active_bool
For Each User_Control In allActiveUserControls
User_Control.Start_Race()
Next
End Sub
I do Google my head off before I post my ridiculous questions here btw :)
This is strange. Does any MsgBoxes pop up if you add this code to your UserControl:
Private Sub UserControl_ControlRemoved(sender As Object, e As System.Windows.Forms.ControlEventArgs) Handles Me.ControlRemoved
MsgBox("Control Removed!")
End Sub
Private Sub Button2_EnabledChanged(sender As Object, e As System.EventArgs) Handles Button2.EnabledChanged
MsgBox("EnabledChanged!")
End Sub
If so, then you can add a breakpoint to these MsgBoxes and lock at the CallStack (CTRL+L) from where it triggers.
Btw: If the control is removed somehow, .PerformClick() still triggers (for me). Thus I bet, that the control is somehow disabled (Enabled = False).
Lastly, if any container of the button (such as your UserControl) is disabled, the button will be disabled too,
After lots of playing around I finally found the problem!
The value was set to =False in my properties. I'm so blonde! Thanks guys for the help ^_^/
Public Property Active_bool As Boolean
Get
Return btn_Begin.Visible
End Get
Set(ByVal value As Boolean)
btn_Begin.Visible = value
End Set
End Property
Although, Something sets the values to =False ever now and then. Very annoying :3
And I can not set the value to =True in the properties... Only in the hidden designer code...

Errorprovider shows error on using windows close button(X)

Is there any way to turn the damned error provider off when i try to close the form using the windows close button(X). It fires the validation and the user has to fill all the fields before he can close the form..this will be a usability issue because many tend to close the form using the (X) button.
i have placed a button for cancel with causes validation to false and it also fires a validation.
i found someone saying that if you use Form.Close() function validations are run...
how can i get past this annoying feature.
i have a MDI sturucture and show the form using
CreateExam.MdiParent = Me
CreateExam.Show()
on the mdi parent's menuitem click
and have this as set validation
Private Sub TextBox1_Validating(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating
If String.IsNullOrEmpty(TextBox1.Text) Then
Err.SetError(TextBox1, "required")
e.Cancel = True
End If
If TextBox1.Text.Contains("'") Then
Err.SetError(TextBox1, "Invalid Char")
e.Cancel = True
End If
End Sub
Any help is much appreciated.
googling only showed results where users were having problem using a command button as close button and that too is causing problem in my case
The ValidateChildren() method prevents the form from closing. Paste this code in your form to fix that:
protected override void OnFormClosing(FormClosingEventArgs e) {
e.Cancel = false;
}
This is quite simple fix, in your Form's Closing Event, set a flag to indicate leaving the form, for example blnLeave, when the Form gets loaded, set the flag to False, when the Closing event gets triggered, set that to True within that event handler, then the change as follows would be
Private Sub TextBox1_Validating(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating
If (blnLeave) Then
e.Cancel = False;
Return
End If
If String.IsNullOrEmpty(TextBox1.Text) Then
Err.SetError(TextBox1, "required")
e.Cancel = True
End If
If TextBox1.Text.Contains("'") Then
Err.SetError(TextBox1, "Invalid Char")
e.Cancel = True
End If
End Sub
Edit: Amended this answer for inclusion as per OP's comments. My suggestion is to handle the Form's Closed Event as shown
Private Sub Form1_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
blnLeave = True
End Sub
And handle it here in the Form's window procedure override as shown here....
Private Const SC_CLOSE As Integer = &HF060
Private Const WM_MENUSELECT As Integer = &H11F
Private Function LoWord(ByVal Num As Integer) As Integer
LoWord = Num & &HFFFF
End Function
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_MENUSELECT Then
If LoWord(m.WParam.ToInt32()) = SC_CLOSE Then
' Handle the closing via system Menu
blnLeave = True
End If
End If
MyBase.WndProc(m)
End Sub