Logic
There is Form1 with a FlowLayoutPanel 'flowItems' to be populated by UserControl 'UCItem'. For populating flowItems, an array is used. For-Loop loopes over the array and creates a new UCItem, gives it a tag name with number and adds it to flowItem. All this part works.
Issue
I want to change the public declared boolean variable 'isChecked' each time the newly created UCItem is clicked. For achieving this, I've added an event handler (UCItem.Click) which gets and sets the property.
How ever, I'm unable to access the public boolean variable in UCItem.
Code: UC_Item.vb
Public isChecked As Boolean = False
Private Sub toggle_color()
If Me.BackColor = Color.FromArgb(24, 24, 24) Then
Me.BackColor = Color.RoyalBlue
Me.txtName.BackColor = Color.RoyalBlue
Me.txtName.ForeColor = Color.Black
Me.BackgroundImage = Nothing
isChecked = True
Else
Me.BackColor = Color.FromArgb(24, 24, 24)
Me.txtName.BackColor = Color.Black
Me.txtName.ForeColor = Color.White
Me.BackgroundImage = Image.FromFile(Application.StartupPath & "/res/UCItem_Wallpaper.png")
isChecked = False
End If
End Sub
Private Sub UC_Item_Click(sender As Object, e As EventArgs) Handles MyBase.Click
toggle_color()
End Sub
Private Sub TxtName_Click(sender As Object, e As EventArgs) Handles txtName.Click
toggle_color()
End Sub
Code: Form1.vb
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim UCItem As UC_Item
flowItems.SuspendLayout()
For i As Integer = 0 To items.Count - 1
UCItem = New UC_Item
UCItem.Tag = "UCItem" & i
UCItem.txtName.Text = items(i).ToString
flowItems.Controls.Add(UCItem)
UCItem.Show() : UCItem.Visible = True
AddHandler(UCItem.Click), AddressOf UCItem_Click
Next
flowItems.ResumeLayout()
End Sub
Private Sub UCItem_Click(sender As Object, ByVal e As EventArgs)
' -- not working part --
' If sender.isChecked = True Then
' sender.isChecked = False
' else
' sender.isChecked = True
End Sub
Tried
I've tried passing 'UCItem As sender.Tag' but this doesn't work too. I can't access the .Tag and .Name property of sender in the click event.
Any help is appreciated!
Related
I have created a custom control (Check Box) with a custom EventHandler
Public Event CheckedChanged As EventHandler
Private Sub setCheckStateUI(sender As Object, e As EventArgs)
...
RaiseEvent CheckedChanged(sender, e)
End Sub
It works fine without any errors if I added this control directly to a form. But when I add this to another custom control (a page of settings window) and that second custom control add to a form (settings window) the 'settings window' freeze and visual studio auto restart.
If I removed this event handler in the code the problem is gone.
What can be the problem here?
Thanks in advance
Update: (Complete code of the Custom Control)
Public Class cusCheckBox
Private mystring As String
Private CheckButtonState As Integer = 0
Public Event CheckedChanged As EventHandler
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
mystring = Me.Name
setSizes()
End Sub
Public Property CheckState() As Integer
Get
CheckState = CheckButtonState
End Get
Set(ByVal value As Integer)
CheckButtonState = value
chkButton.CheckState = CheckButtonState
End Set
End Property
Public Property LabelText() As String
Get
LabelText = mystring
End Get
Set(ByVal value As String)
mystring = value
lblText.Text = mystring
setSizes()
End Set
End Property
Public Overrides Property Font As Font
Get
Return lblText.Font
End Get
Set(value As Font)
lblText.Font = value
End Set
End Property
Private Sub chkButton_CheckedChanged(sender As Object, e As EventArgs) Handles chkButton.CheckedChanged
If chkButton.CheckState = 1 Then
chkButton.Image = Global.MYLogs.My.Resources.Resources.btnToggleOn
CheckButtonState = 1
Else
chkButton.Image = Global.MYLogs.My.Resources.Resources.btnToggleOff
CheckButtonState = 0
End If
End Sub
Private Sub lblText_Click(sender As Object, e As EventArgs) Handles lblText.Click
setCheckStateUI(sender, e)
End Sub
Private Sub cusCheckBox_MouseClick(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
setCheckStateUI(sender, e)
End Sub
Private Sub cusCheckBox_Load(sender As Object, e As EventArgs) Handles MyBase.Load
setCheckStateUI(sender, e)
setSizes()
End Sub
Private Sub cusCheckBox_Resize(sender As Object, e As EventArgs) Handles Me.Resize
setSizes()
End Sub
Private Sub setSizes()
Me.Size = New Size(chkButton.Width + lblText.Width + 4, chkButton.Height)
End Sub
Private Sub setCheckStateUI(sender As Object, e As EventArgs)
If chkButton.CheckState = 0 Then
chkButton.Image = Global.MYLogs.My.Resources.Resources.btnToggleOn
chkButton.CheckState = 1
CheckButtonState = 1
Else
chkButton.Image = Global.MYLogs.My.Resources.Resources.btnToggleOff
chkButton.CheckState = 0
CheckButtonState = 0
End If
RaiseEvent CheckedChanged(Me, EventArgs.Empty)
chkButton.Select()
End Sub
End Class
I am loading a form with values from stored settings from the registry
Typically :
If sFormat = TG_ReportFormatDft Then
RadioButton1.Checked = True
........
Else
RadioButton2.Checked = True
..........
End If
TG_ReportFormatDft is a string constant and is of no significance. The radio buttons are grouped correctly and manually clicked behave correctly.
Later in the procedure I check if there has been a manual change :
'Follow what the user is doing
Private Sub RadioButton1_Click(sender As Object, e As EventArgs) Handles RadioButton1.Click
msReports_Format2 = TG_ReportFormatDft
DoButtons(True)
End Sub
Private Sub RadioButton2_Click(sender As Object, e As EventArgs) Handles RadioButton2.Click
msReports_Format2 = TG_ReportFormatAlt
DoButtons(True)
End Sub
Imagine my surprise when these downstream subroutines are triggered without a mouse click. It would appear that :
RadioButton1.Checked = True --- triggers the mouse click event.
I can understand an 'On Change' event but the mouse click has not happened.
How can I prevent this 'click' event from propagating ?
Declare a class level boolean variable "ClickedFromCode". Now when you are setting the values from code set the boolean to true. See below sample code.
Private ClickedFromCode As Boolean
Private Sub Intialize
ClickedFromCode = True
If sFormat = TG_ReportFormatDft Then
RadioButton1.Checked = True
Else
RadioButton2.Checked = True
End If
ClickedFromCode = False
End Sub
Private Sub RadioButton1_Click(sender As Object, e As EventArgs) Handles RadioButton1.Click
If ClickedFromCode Then
Return
End If
msReports_Format2 = TG_ReportFormatDft
DoButtons(True)
End Sub
Private Sub RadioButton2_Click(sender As Object, e As EventArgs) Handles RadioButton2.Click
If ClickedFromCode Then
Return
End If
msReports_Format2 = TG_ReportFormatAlt
DoButtons(True)
End Sub
I am using a PictureBox inside a button click event. When the button is clicked I am enabling the PictureBox and I am running a long database call and at the end of the process, I am trying to disable the PictureBox. Inside the PictureBox I have a loading GIF.
But I don't know what's happening. My PictureBox does not show up..
Please suggest how can I fix this. I tried Thread.Sleep(1000), but it didn't work.
Private Sub btnRetrieve_Click(sender As Object, e As EventArgs) Handles btnRetrieve.Click
Me.PictureBox1.Visible = True
lblSuccess.Text = Nothing
UltraNumberOfConveyance.Value = Nothing
GetData() --Long Running Query
Me.PictureBox1.Visible = False
End Sub
My GetData Function:
Private Function GetData()
dsCheckPointTimes = GetCheckPointTimesByTerminalID()
dtDataTable = dsCheckPointTimes.Tables(0)
chkdtDataTable = dsCheckPointTimes.Tables(1)
If Not DBNull.Value.Equals(chkdtDataTable.Rows.Item(0).Item("ConveyanceName")) Then
lblConveyanceNameText.Text = chkdtDataTable.Rows.Item(0).Item("ConveyanceName").ToString()
End If
If Not DBNull.Value.Equals(chkdtDataTable.Rows.Item(0).Item("NumberOfConveyance")) Then
UltraNumberOfConveyance.Value = chkdtDataTable.Rows.Item(0).Item("NumberOfConveyance")
End If
If Not DBNull.Value.Equals(chkdtDataTable.Rows.Item(0).Item("Dock")) Then
UltratxtChangeLabel1.Value = chkdtDataTable.Rows.Item(0).Item("Dock")
End If
If Not DBNull.Value.Equals(chkdtDataTable.Rows.Item(0).Item("Lines")) Then
UltratxtChangeLabel2.Value = chkdtDataTable.Rows.Item(0).Item("Lines")
End If
If Not DBNull.Value.Equals(chkdtDataTable.Rows.Item(0).Item("CHECKPOINTTYPE")) Then
SetFields(chkdtDataTable.Rows.Item(0).Item("CHECKPOINTTYPE"))
End If
If dtDataTable.Rows.Count > 0 Then
LoadFlow()
Else
lblSuccess.Text = "No Records Found! Please check the ordernumber"
lblSuccess.ForeColor = Color.Red
End If
Return Nothing
End Function
Use a BackgroundWorker to do this:
Private WithEvents bgw As New BackgroundWorker
Private Sub btnRetrieve_Click(sender As Object, e As EventArgs) Handles btnRetrieve.Click
PictureBox1.Visible = True
bgw.RunWorkerAsync()
End Sub
Private Sub bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgw.DoWork
GetData() --Long Running Query
End Sub
Private Sub bgw_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
PictureBox1.Visible = False
End Sub
This solution seems to be the best one out there and the most commonly accepted one - however, if you scroll to the bottom and touch a the actual flowcontrol behind the buttons (I tried to make this so that there would be empty space to make this sample test easier), you then have to double tap-and-hold the button for the scrolling to resume. Restarting the application restores the phone-like scrolling functionality. I am wondering if anyone else has seen this or figured it out - try it with your apps and see if it is the case as well. I modified the snippet above so that you can start a new project, copy and paste this into form1's code, and hit run.
Public Class Form1
Dim FlowPanel As New FlowLayoutPanel
Private Function GenerateButton(ByVal pName As String) As Button
Dim mResult As New Button
With mResult
.Name = pName
.Text = pName
.Width = 128
.Height = 128
.Margin = New Padding(0)
.Padding = New Padding(0)
.BackColor = Color.CornflowerBlue
AddHandler .MouseDown, AddressOf Button_MouseDown
AddHandler .MouseMove, AddressOf Button_MouseMove
End With
Return mResult
End Function
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
Me.Width = 806
Me.Height = 480
FlowPanel.Padding = New Padding(0)
FlowPanel.Margin = New Padding(0)
' FlowPanel.ColumnCount = Me.Width / (128 + 6)
FlowPanel.Dock = DockStyle.Fill
FlowPanel.AutoScroll = True
Me.Controls.Add(FlowPanel)
Dim i As Integer
For i = 1 To 98
FlowPanel.Controls.Add(GenerateButton("btn" & i.ToString))
Next
End Sub
Dim myMouseDownPoint As Point
Dim myCurrAutoSMouseDown As Point
Private Sub Button_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
myMouseDownPoint = PointToClient(Cursor.Position)
myCurrAutoSMouseDown = FlowPanel.AutoScrollPosition
End Sub
Private Sub Button_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim mLocation As Point = PointToClient(Cursor.Position)
If myMouseDownPoint <> mLocation Then
Dim mCurrAutoS As Point
Dim mDeslocation As Point = myMouseDownPoint - mLocation
mCurrAutoS.X = Math.Abs(myCurrAutoSMouseDown.X) + mDeslocation.X
mCurrAutoS.Y = Math.Abs(myCurrAutoSMouseDown.Y) + mDeslocation.Y
FlowPanel.AutoScrollPosition = mCurrAutoS
End If
End If
End Sub
End Class
Thanks for the code , I made some changes to improve behavior . I hope it can be useful to someone .
Dim myMouseDownPoint As Point
Dim myCurrAutoSMouseDown As Point
'Add boolean variable a true.
Private _ValidateClickEvent As Boolean = True
Private Sub MyMouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
myMouseDownPoint = PointToClient(Cursor.Position)
myCurrAutoSMouseDown = Panel1.AutoScrollPosition
End Sub
' Add MouseUp event for return the boolean variable a true.
Private Sub MyMouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
_ValidateClickEvent = True
End Sub
'Set boolean variable a false when change mlocation.
Private Sub MyMouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim mLocation As Point = PointToClient(Cursor.Position)
If myMouseDownPoint <> mLocation Then
Dim mCurrAutoS As Point
Dim mDeslocation As Point = CType(myMouseDownPoint - mLocation, Size)
mCurrAutoS.X = Math.Abs(myCurrAutoSMouseDown.X) + mDeslocation.X
mCurrAutoS.Y = Math.Abs(myCurrAutoSMouseDown.Y) + mDeslocation.Y
Panel1.AutoScrollPosition = mCurrAutoS
_ValidateClickEvent = False
End If
End If
End Sub
' Test boolean variable to perform click event.
Private Sub MyClick(sender As System.Object, e As System.EventArgs)
If _ValidateClickEvent Then
........................
Else
_ValidateClickEvent = True
End If
End Sub
In VB.NET I'm looking to build a "Time" grid very similar to the Time Restriction grid of the Parental Section of Windows: http://www.thinkbroadband.com/images/guides/time-restrictions.png
It needs to toggle between 2 colors on cell-click
I've played around with One-Cell = One-Label and it kinda works but, like the Windows Time Restriction grid, I'd like to have the labels change colors if I move over the label whilst having the left button pressed (and not only on label click).
Here is what I currently have:
Private Sub ColorToggle(sender As Object, e As MouseEventArgs) Handles Label1.Click, Label2.Click, Label3.Click 'etc..
If e.Button = Windows.Forms.MouseButtons.Left Then
sender.backcolor = If(sender.backcolor = SystemColors.Control, Color.LightGreen, SystemColors.Control)
End If
End Sub
Since the sender stays the same when I hover the labels (sender = label I've originally clicked on), this code doesn't work for my purpose.
I'm looking for suggestions!
Thanks :)
When you click on a control and you hold the mouse button down, this control captures the following mouse events, so that you won't get events from the other lables when moving the mouse over them.
The trick is to set label.Capture = False.
Lets define colors:
Private ReadOnly selectedColor As Color = Color.Blue
Private ReadOnly unselectedColor As Color = Color.White
And Booleans storing the current state of our operations
Private isSelecting As Boolean = False
Private isUnselecting As Boolean = False
(All four as fields of the form class)
Now lets write these three event handlers:
Private Sub Label_MouseDown(sender As Object, e As EventArgs)
'This event starts selecting/unselecting
Dim label = DirectCast(sender, Label)
label.Capture = False '<=== THIS IS IMPORTANT!
If label.BackColor = selectedColor Then
isUnselecting = True
Else
isSelecting = True
End If
SelectLabel(label)
End Sub
Private Sub Label_MouseUp(sender As Object, e As EventArgs)
'This event stops selecting/unselecting
isSelecting = False
isUnselecting = False
End Sub
Private Sub Label_MouseEnter(sender As Object, e As EventArgs)
SelectLabel(DirectCast(sender, Label))
End Sub
And we need this procedure that selects or unselects the labels:
Private Sub SelectLabel(label As Label)
If isSelecting Then
label.BackColor = selectedColor
ElseIf isUnselecting Then
label.BackColor = unselectedColor
End If
End Sub
That's it!
Footnote: I have created the lables like this:
Private Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Const w As Integer = 50, h As Integer = 50
For x = 1 To 10
For y = 1 To 10
Dim lbl As New Label() With {
.Location = New Point(x * w, y * h),
.Size = New Size(w, h),
.BorderStyle = BorderStyle.FixedSingle,
.BackColor = unselectedColor
}
AddHandler lbl.MouseDown, AddressOf Label_MouseDown
AddHandler lbl.MouseUp, AddressOf Label_MouseUp
AddHandler lbl.MouseEnter, AddressOf Label_MouseEnter
Controls.Add(lbl)
Next
Next
End Sub
I hope this isn't homework...
Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
Dim i As Integer
With dgv
.ColumnCount = 0
.DataSource = Nothing
.Columns.Add("Day", "Day")
For i = 0 To 23
.Columns.Add(i, i)
.Columns(.Columns.Count - 1).Width = 30
Next
For i = 1 To 7
.Rows.Add({i})
Next
End With
End Sub
Private Sub dgv_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgv.CellClick
dgv.CurrentCell.Style.BackColor = Color.Blue
End Sub
Here is a drag version:
Private Sub dgv_MouseUp(sender As Object, e As MouseEventArgs) Handles dgv.MouseUp
For Each cell As DataGridViewCell In dgv.SelectedCells
If cell.Style.BackColor = Color.Blue Then
cell.Style.BackColor = Color.White
Else
cell.Style.BackColor = Color.Blue
End If
Next
dgv.ClearSelection()
End Sub