I have a need to swap controls in a TableLayoutPanel. They are in separate rows. I've tried the suggested code but to no avail. Is there a solution this other than removing all the controls and re adding? The answer can be in C# or VB.
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
Dim c1 As Control = Me.tlp.GetControlFromPosition(0, 0)
Dim c2 As Control = Me.tlp.GetControlFromPosition(0, 1)
If c1 IsNot Nothing And c2 IsNot Nothing Then
Me.tlp.SetRow(c2, 0)
Me.tlp.SetRow(c1, 1)
End If
End Sub
Here is the code to swap controls in a TableLayoutPanel - you have two options.
1) Swap by reference to controls:
Private Sub SwapControls(tlp As TableLayoutPanel, ctl1 As Control, ctl2 As Control)
Dim ctl1pos As TableLayoutPanelCellPosition = tlp.GetPositionFromControl(ctl1)
tlp.SetCellPosition(ctl1, tlp.GetPositionFromControl(ctl2))
tlp.SetCellPosition(ctl2, ctl1pos)
End Sub
It does not depend on where controls are located in TableLayoutPanel - could be different rows, columns or both.
Sample usage:
SwapControls(TableLayoutPanel1, Button1, Button2)
2) Swap by column/row index:
Private Sub SwapControls(tlp As TableLayoutPanel, pos1 As TableLayoutPanelCellPosition, pos2 As TableLayoutPanelCellPosition)
Dim ctl1 As Control = tlp.GetControlFromPosition(pos1.Column, pos1.Row)
Dim ctl2 As Control = tlp.GetControlFromPosition(pos2.Column, pos2.Row)
SwapControls(tlp, ctl1, ctl2)
End Sub
Sample usage:
SwapControls(TableLayoutPanel1, New TableLayoutPanelCellPosition(0, 0), New TableLayoutPanelCellPosition(1, 0))
Solutions are based around TableLayoutPanel.SetRow help article on MSDN and some research on its decompiled representation. Both were tested and deemed working.
If you have fixed length TableLayoutPanel, you may use FlowLayoutPanel (then length of it controls must have equal FlowLayoutPanel length):
Dim c1 As Control = Button1
Dim c2 As Control = CheckBox1
Dim i1 = FlowLayoutPanel1.Controls.IndexOf(c1)
Dim i2 = FlowLayoutPanel1.Controls.IndexOf(c2)
FlowLayoutPanel1.Controls.SetChildIndex(c1, i2)
FlowLayoutPanel1.Controls.SetChildIndex(c2, i1)
Same in C# code:
swapping / exchanging controls at any positions 1 and 2:
private void SwapControls(TableLayoutPanel tlp, TableLayoutPanelCellPosition cpos1, TableLayoutPanelCellPosition cpos2)
{
var ctl1 = tlp.GetControlFromPosition(cpos1.Column, cpos1.Row);
var ctl2 = tlp.GetControlFromPosition(cpos2.Column, cpos2.Row);
if (ctl1 != null) // position1 can be empty
tlp.SetCellPosition(ctl1, cpos2);
if (ctl2 != null) // position2 can be empty
tlp.SetCellPosition(ctl2, cpos1);
}
Sample of usage:
SwapControls(TableLayoutPanel1, new TableLayoutPanelCellPosition(0, 0), new TableLayoutPanelCellPosition(1, 0))
After searching around for a day and not coming up with nothing I finally took a shot in the dark and found the answer. You need to use the SetChildIndex of the control in the table. See Below...
Note: this only works if you add controls to TableLayoutPanel without row or column index.
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
tlp.RowStyles.Clear()
For i As Integer = 0 To 4
Dim txt As New TextBox
txt.Text = i
txt.Name = "txt" & i
tlp.Controls.Add(txt) 'this works
'tlp.Controls.Add(txt, 0, i) 'this will not work when button is clicked
Next
End Sub
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
Dim c1 As Control = Me.tlp.GetControlFromPosition(0, 0)
Dim c2 As Control = Me.tlp.GetControlFromPosition(0, 1)
If c1 IsNot Nothing And c2 IsNot Nothing Then
tlp.Controls.SetChildIndex(c1, 1)
tlp.Controls.SetChildIndex(c2, 0)
End If
End Sub
Related
I ha a form referenced like:
MainForm= Form1;
but in another method same class; after detecting that system have more that 1 monitor:
int screens = Screen.AllScreens.Length;
if (screens > 1)
{
model.AddItem((CefMenuCommand)26504, "Switch Screen (Monitor)");
model.AddSeparator();
}
I need to switch between these:
Screen[] lsScreen = Screen.AllScreens;
Screen myScreen = Screen.FromControl(MainForm);
if(myScreen == lsScreen[1])
{
MainForm.Location = lsScreen[0].WorkingArea.Location; // Primary Screen
MainForm.Top = MainForm.Left = 0;
MainForm.Width = lsScreen[0].WorkingArea.Width;
MainForm.Height = lsScreen[0].WorkingArea.Height;
}
else
{
MainForm.Location = lsScreen[1].WorkingArea.Location; // Secondary Screen
MainForm.Width = lsScreen[1].WorkingArea.Width;
MainForm.Height = lsScreen[1].WorkingArea.Height;
}
Update
this is that Visual Studio 2019 show:
works partially correct; since I can move the application from the primary screen to the secondary one; the problem is that I can't move from the secondary screen to the primary one (Return); It seems to me that the error is in the last piece of code, that I cannot determine what it is.
the other limitation is that it only works between two screens; primary and secondary; How can I adapt my code to improve it so that it supports an indeterminate number of screen ...
Solution of the first question:
replace this:
if(myScreen == lsScreen[1])
with this:
if(myScreen.DeviceName == lsScreen[1].DeviceName)
Pending Improvement / Second question.
Here's some code from an app I wrote that dynamically populates a ContextMenuStrip with all the other monitors that something can be sent to. It might give you some ideas on how to approach this:
Private Sub ContextMenuStrip1_Opening(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles ContextMenuStrip1.Opening
If Screen.AllScreens.Count > 1 Then
SendToToolStripMenuItem.DropDownItems.Clear()
SendToToolStripMenuItem.Visible = True
Dim containingScreen As Screen = Screen.FromHandle(Me.Handle)
For i As Integer = 0 To Screen.AllScreens.Count - 1
Dim curScreen As Screen = Screen.AllScreens.ElementAt(i)
If curScreen.DeviceName <> containingScreen.DeviceName Then
Dim screenMenu As New ToolStripMenuItem(curScreen.DeviceName)
screenMenu.Tag = i
AddHandler screenMenu.Click, AddressOf ScreenMenu_Click
SendToToolStripMenuItem.DropDownItems.Add(screenMenu)
End If
Next
End If
End Sub
Private Sub ScreenMenu_Click(sender As Object, e As EventArgs)
Dim screenMenu As ToolStripMenuItem = DirectCast(sender, ToolStripMenuItem)
Dim index As Integer = screenMenu.Tag
Me.SendToScreen(index)
End Sub
Public Sub SendToScreen(ByVal index As Integer)
If index < 0 OrElse index > (Screen.AllScreens.Count - 1) Then
index = 0
End If
Dim curScreen As Screen = Screen.FromHandle(Me.Handle)
Dim destScreen As Screen = Screen.AllScreens.ElementAt(index)
Dim ptF As New PointF((CDbl(Me.Location.X) - curScreen.Bounds.Left) / curScreen.Bounds.Width,
(CDbl(Me.Location.Y) - curScreen.Bounds.Top) / curScreen.Bounds.Height)
Dim szF As New PointF(CDbl(Me.Width) / curScreen.Bounds.Width,
CDbl(Me.Height) / curScreen.Bounds.Height)
Dim destPt As New Point(destScreen.Bounds.Left + ptF.X * destScreen.Bounds.Width,
destScreen.Bounds.Top + ptF.Y * destScreen.Bounds.Height)
Dim destSz As New Size(destScreen.Bounds.Width * szF.X, destScreen.Bounds.Height * szF.Y)
Me.Location = destPt
Me.Size = destSz
End Sub
Here's what it looks like when the menu is displayed on my system with three monitors (sometimes I have four total connected and it works great then, too):
Tags wouldn't be the correct word for what I'm looking for, but for lack of a better choice, it's what I've used. What I'd like to know is if there's a component or anything I can use that will create an input similar to this site's tags field.
Basically I would like a field exactly like the one used here. As you type in a list of possible options becomes available and once one is selected, you can continue to select another. Unless it's under a name I have not yet thought of, I have not been able to find one in any of my searches.
Is there anyway I can get what I want?
As I wrote in my comment, its very simple to do it by yourself (took me only ~15 min to write you the example below) here is a code example+output for start - "Tag label" object with a button to dispose himself, please read my comments inside.
clarification: this code needs improvements to be adapted to all possible cases but you can learn from it the basic idea of how to create a custom control.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
FlowLayoutPanel1.Padding = New Padding(3, 3, 3, 3)
Dim g As Graphics = Me.CreateGraphics()
Dim size As SizeF
' check how much width needed for the string "Winforms"...'
size = g.MeasureString("Winforms", Me.Font)
Dim tagwinforms As New TagObject("Winforms", size.Width + TagObject.BtnRemoveWidth + 20, FlowLayoutPanel1.Height - 8)
tagwinforms.Init()
FlowLayoutPanel1.Controls.Add(tagwinforms)
' check how much width needed for the string "C#"...'
size = g.MeasureString("C#", Me.Font)
Dim tagcsharp As New TagObject("C#", size.Width + TagObject.BtnRemoveWidth + 20, FlowLayoutPanel1.Height - 8)
tagcsharp.Init()
FlowLayoutPanel1.Controls.Add(tagcsharp)
g.Dispose()
End Sub
End Class
Public Class TagObject
Inherits Label
Public Shared Property BtnRemoveWidth As Int16 = 20
Public Shared Property BtnRemoveHeight As Int16 = 20
' note: you can add get set methods and in the set method you can change value in runtime '
Public Property DescriptionText As String
Private Property TagHeight As Int16
Private Property TagWidth As Int16
Private btnRemove As PictureBox
' you can add any property you need backcolor forecolor etc...'
Sub New(ByVal descriptionText As String, ByVal width As Int16, ByVal height As Integer)
Me.DescriptionText = descriptionText
Me.TagHeight = height
Me.TagWidth = width
Me.Font = New Font("ARIAL", 8, FontStyle.Bold)
End Sub
Public Sub Init()
Me.Text = DescriptionText
Me.Width = TagWidth
Me.Height = TagHeight
Me.TextAlign = ContentAlignment.MiddleCenter
Me.BackColor = Color.FromArgb(30, 30, 30)
Me.ForeColor = Color.White
btnRemove = New PictureBox()
btnRemove.Height = BtnRemoveHeight
btnRemove.Width = BtnRemoveWidth
btnRemove.Location = New Point(TagWidth - btnRemove.Width - 1, TagHeight / 2 - btnRemove.Height / 2)
' original image url: https://www.google.co.il/search?q=close+icon+free&safe=off&rlz=1C1ASUM_enIL700IL700&source=lnms&tbm=isch&sa=X&ved=0ahUKEwjVuJnbk5vZAhXKesAKHRXqDX8Q_AUICigB&biw=1440&bih=769#imgrc=2p_iHiqieStqCM:'
btnRemove.Image = My.Resources.CloseIcon
btnRemove.Cursor = Cursors.Hand
AddHandler btnRemove.Click, AddressOf btnRemove_Click
Me.Controls.Add(btnRemove)
End Sub
Private Sub btnRemove_Click(sender As Object, e As EventArgs)
' the user wants to delete this tag...'
Me.Dispose()
End Sub
End Class
Output:
I've inherited a Listview to perform some minor changes but I would like to improve the design in the usercontrol Class or anywhere in the Form Class 'cause I'm not happy with the default resizing mechanism of a Listview.
In the Form Class I resize the last column ("Download") like this:
ColumnDownload.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize)
The problem is that when the (default) scrollbar appears inside the listview the size of the last column is not automatically fixed/decreased so an horizontal and uneedded scrollbar automatically appears too.
Then someone could help me please to explain me how can be done this to auto-fix the size of the last column when the scrollbar appears? I'm very lost about that.
NOTE: I need to say that I'm not looking for alternative LV's such as ObjectListView.
NOTE 2: I don't show my usercontrol class 'cause I'm not performing any auto-resize improvement at the moment there, I don't know where to start.
This is my Listview as normal:
And this is the same listview filled with items:
when the (default) scrollbar appears inside the listview the size of the last column is not automatically fixed/decreased ... "default scrollbar" taken to mean the Veritical Scroll.
AutoResize is not AutoFit. It is for sizing columns based on the Header text extent or content length, not managing scrollbars and works very well. If it did automatically resize the last column, we would be angry when the last column is a small 'OK?' type column which was rendered unreadable when it was AutoFitted away.
PInvokes in a NativeMethods class; these eat scrollbars and get whether they are showing or not.
Public Const WS_VSCROLL As Integer = &H200000
Public Const WS_HSCROLL As Integer = &H100000
Friend Enum SBOrientation As Integer
SB_HORZ = &H0
SB_VERT = &H1
SB_CTL = &H2
SB_BOTH = &H3
End Enum
<DllImport("user32.dll")> _
Private Shared Function ShowScrollBar(ByVal hWnd As IntPtr,
ByVal wBar As Integer,
<MarshalAs(UnmanagedType.Bool)> ByVal bShow As Boolean
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetWindowLong(ByVal hWnd As IntPtr,
ByVal nIndex As Integer) As Integer
End Function
Friend Shared Function IsHScrollVisible(ByVal ctl As Control) As Boolean
Dim wndStyle As Integer = GetWindowLong(ctl.Handle, GWL_STYLE)
Return ((wndStyle And WS_HSCROLL) <> 0)
End Function
Friend Shared Function IsVScrollVisible(ByVal ctl As Control) As Boolean
Dim wndStyle As Integer = GetWindowLong(ctl.Handle, GWL_STYLE)
Return ((wndStyle And WS_VSCROLL) <> 0)
End Function
Friend Shared Sub ShowHideScrollBar(ByVal ctl As Control,
ByVal sb As SBOrientation, ByVal bShow As Boolean)
ShowScrollBar(ctl.Handle, sb, bShow)
End Sub
Steal xx pixels from the last column; Put the pixels back if the VScroll goes away.
Basically what happens is that ClientSizeChanged fires twice: 1) when the VScroll arrives then again a few micros later when the HScroll arrives as a result of the VScroll. So you have to process the event twice. This resizes the desired column in the first pass, and eats the HScroll in the second one. Even though the HScroll is no longer needed after Step 1, it shows up briefly if you dont remove it manually.
If an HScroll is needed due to the way you laid it out or from the user resizing columns, it will resize the last column anyway, but not eat the HScroll. The extra logic to detect when the first step is not needed is missing (you cant see that it does it, normally).
Caveats: I have no idea how or if this will work with this 3rd party theme. I dont think that the themes can modify internal scrollbars like these.
Also, this is intended for use in a subclassed LV, which I know you have already done. For others, with some reworking of references, this should also work on a form to 'push' the changes using the related events (e.g. ClientSizeChanged) even if it leaves a lot of ugly code in the form.
This also isnt wrapped in something like an IF AutoFit property test.
Private orgClient As Rectangle ' original client size for comparing
Private _VScrollWidth As Integer
Private _resizedCol As Integer = -1
Private _VScroll As Boolean = False ' persistent Scroll flags
Private _HScroll As Boolean = False
' 3rd party???
_VScrollWidth = System.Windows.Forms.SystemInformation.VerticalScrollBarWidth
Put this somewhere like ISupportInitialize.EndInit:
orgClient = Me.ClientRectangle
Sub New is not a good place for orgClient - the control hasnt been created yet. OnHandleCreated will do, but without ISupportInitialize, I would invoke a new Sub on the control to set it from Form_Load instead. This can actually be handy to have, if you want to 'restart' things after manually resizing columns then back again. For example:
' method on subclassed LV: from form load: thisLV.ResetClientSize
Public Sub ResetClientSize
orgClient = Me.ClientRectangle
End Sub
' a helper:
Private Function AllColumnsWidth() As Integer
Dim w As Integer = 0
For Each c As ColumnHeader In Columns
w += c.Width
Next
Return w
End Function
' The Meat
Protected Overrides Sub OnClientSizeChanged(ByVal e As System.EventArgs)
Dim VScrollVis As Boolean
Dim HScrollVis As Boolean
' get who is Now Showing...local vars
VScrollVis = NativeMethods.IsVScrollVisible(Me)
HScrollVis = NativeMethods.IsHScrollVisible(Me)
' width change
Dim delta As Integer = (orgClient.Width - ClientRectangle.Width)
Dim TotalWidth As Integer = AllColumnsWidth()
If (TotalWidth < ClientRectangle.Width - _VScrollWidth) And
(_resizedCol = -1) Then
Exit Sub
End If
Me.SuspendLayout()
' If VScroll IS showing, but WASNT showing the last time thru here
' ... then we are here because VScroll just appeared.
' That being the case, trim the desired column
If VScrollVis And _VScroll = False Then
' a smarter version finds the widest column and resizes THAT one
_resizedCol = Columns.Count - 1
' we have to wait for the HScroll to show up
' to remove it
Columns(_resizedCol).Width -= (delta + 1)
End If
' HScroll just appeared
If HScrollVis And (delta = _VScrollWidth) Then
' HScroll popped up, see if it is needed
If AllColumnsWidth() <= orgClient.Width Then
' no, go away foul beast !
NativeMethods.ShowHideScrollBar(Me,
NativeMethods.SBOrientation.SB_HORZ, False)
_HScroll = False ' hopefully
' allows us to set it back if the VScroll disappears
orgClient = ClientRectangle
Else
' ToDo: use this to detect when none of this is needed
_HScroll = HScrollVis
End If
End If
' If VScroll ISNOT showing, but WAS showing the last time thru here
' ...then we are here because VScroll disappeared
If VScrollVis = False And _VScroll = True Then
' put back the pixels
If _resizedCol <> -1 Then
Columns(_resizedCol).Width += (_VScrollWidth + 1)
' reset column tracker
_resizedCol = -1
' reset to new compare size
orgClient = ClientRectangle
End If
End If
_VScroll = VScrollVis
Me.ResumeLayout()
End Sub
More or less I have it done so I'll post this solution, something still wrong with the code 'cause it is not working as expected in some cases where I've tried to "play" showing and hidding the scrollbars it can hang the listview, and sure the code has unneded checks and can be improved but now I don't have more time to try to fix the related issues, if someone could help to fix this code to improve it then thankyou so much:
Dim SizeAlreadyDecreased As Boolean = False
Private Sub ElektroListView_Downloads_ClientSizeChanged(sender As Object, e As EventArgs) _
Handles ElektroListView_Downloads.ClientSizeChanged
' Retrieve all the column widths
Dim AllColumnsWidth As Integer =
(From col As ColumnHeader In CType(sender.Columns, ListView.ColumnHeaderCollection)
Select col.Width).Sum
' Fix the last column width to fill the not-used blank space when resizing the Form.
Me.ColumnDownload.Width =
Me.ColumnDownload.Width + (sender.ClientSize.Width - AllColumnsWidth) - 2
' Fix the last column width to increase or decrease the size if a VertivalScrollbar appears.
If GetScrollbars(sender) AndAlso Not SizeAlreadyDecreased Then
SizeAlreadyDecreased = True
ColumnDownload.Width -= SystemInformation.VerticalScrollBarWidth
ElseIf GetScrollbars(sender) AndAlso SizeAlreadyDecreased Then
SizeAlreadyDecreased = True
ElseIf Not GetScrollbars(sender) AndAlso SizeAlreadyDecreased Then
SizeAlreadyDecreased = False
ColumnDownload.Width += SystemInformation.VerticalScrollBarWidth
ElseIf Not GetScrollbars(sender) AndAlso Not SizeAlreadyDecreased Then
SizeAlreadyDecreased = False
End If
End Sub
Private Const WS_VSCROLL As Integer = &H200000I
Private Const WS_HSCROLL As Integer = &H100000I
Private Const GWL_STYLE As Integer = -16I
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Private Shared Function GetWindowLong(
ByVal hWnd As HandleRef,
ByVal nIndex As Integer
) As Integer
End Function
Public Function GetScrollbars(ByVal ctrl As Control) As ScrollBars
Dim style As Integer = GetWindowLong(New HandleRef(ctrl, ctrl.Handle), GWL_STYLE)
Dim HScroll As Boolean = ((style And WS_HSCROLL) = WS_HSCROLL)
Dim VScroll As Boolean = ((style And WS_VSCROLL) = WS_VSCROLL)
If (HScroll AndAlso VScroll) Then
Return ScrollBars.Both
ElseIf HScroll Then
Return ScrollBars.Horizontal
ElseIf VScroll Then
Return ScrollBars.Vertical
Else
Return ScrollBars.None
End If
End Function
I have a DataGridView which contains a DataGridViewColumn and also a button. When I click the button I want to check if all checkboxes in the datagridview are checked or not.
I use the following code but it is not working:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
For i As Integer = 0 To DataGridView1.Rows.Count - 1
Dim CheckBox As DataGridViewCheckBoxCell = DirectCast(DataGridView1.Rows(i).Cells(0), DataGridViewCheckBoxCell)
If Not CheckBox.Value = Not CheckBox.Value Then
MsgBox("True")
End If
Next
End Sub
I think you have a problem with your IF statement. It should be checking if Value = True instead of .value = Not Checkbox,Value
If CheckBox.Value = True Then
MsgBox("True")
End If
I can't really tell what your logic is supposed to be doing with this line:
If Not CheckBox.Value = Not CheckBox.Value Then
It looks like you are saying, "if Not Value = Not Value" ???
Try this:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
For i As Integer = 0 To DataGridView1.Rows.Count - 1
'Dim CheckBox As DataGridViewCheckBoxCell = DirectCast(DataGridView1.Rows(i).Cells(0), DataGridViewCheckBoxCell)
'If Not CheckBox.Value = Not CheckBox.Value Then
' MsgBox("True")
'End If
Dim obj As Object = DataGridView1.Rows(i).Cells(0)
If (Not obj Is Nothing) Then
Dim checkBox1 As DataGridViewCheckBoxCell = DirectCast(obj, DataGridViewCheckBoxCell)
Dim objValue As Object = checkBox1.Value
If (Not objValue Is Nothing) Then
Dim checked As Boolean = DirectCast(objValue, Boolean)
If (checked) Then
MsgBox("True")
End If
End If
End If
Next
End Sub
I need a component in .net which able me to partition a year to some part which is making by clicking at the beginning of the part and click again at the end of that.
the shape below is a sample of my need but I create it by buttons and back-color of them for showing for you:
alt text http://www.imagechicken.com/uploads/1274539634038682400.png
I don't know the name of this component to search for that.
does anyone know this component or something like this?
thank you
I'm sure the code can be cleaned up a little, but your question inspired me to actually do something in reflection. I use reflection in this code to where you name each button "Button1", "Button2", "Button3", etc. You can have 365 for all the days in the year, just make sure you change the variable intTotalButtonCount to however many buttons you have in your app. This will allow the user to click a start button and it will change its backcolor to red. When the user selects a finish button, it will change the color of all of the buttons in between the start and finish to red. A user can change the finish button (it will update the colors) or reselect the start button or one prior to it to start from scratch, which will change it back to the default control color (which it grabs from a generic save button named "btnSaveVacation"). (Notice that Button1_Click handles every single buttonX_Click event, so if you have 365 buttons, you will have to make sure that Button_1 click handles all of them.)
Dim intStart As Integer = 0
Dim intFinish As Integer = 0
Dim intButtonPushed As Integer = 0
Private Sub UpdateControls(ByVal Start As Integer, ByVal Finish As Integer, ByVal ButtonColor As Color)
Dim myButton As Button
For X = Start To Finish
myButton = Me.Controls("Button" & X.ToString)
myButton.BackColor = ButtonColor
Next
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click, Button2.Click, Button3.Click
Dim property_value As Object
Dim X As Integer = 0
Dim strButtonName As String = ""
Dim properties_info As PropertyInfo() = GetType(Button).GetProperties()
Dim intTotalButtonCount As Integer = 3 'Total number of buttons
For i As Integer = 0 To properties_info.Length - 1
With properties_info(i)
If .GetIndexParameters().Length = 0 Then
property_value = .GetValue(sender, Nothing)
If property_value Is Nothing Then
Else
If .Name = "Text" Then
strButtonName += property_value.ToString
intButtonPushed = CInt(Mid(strButtonName, 7, (Len(strButtonName) - 6)))
Dim myButton As Button = Me.Controls(strButtonName)
If intStart < 1 Then
intStart = intButtonPushed
myButton.BackColor = Color.Red
Else
If intStart = intButtonPushed Then
UpdateControls(1, intTotalButtonCount, btnSaveVacation.BackColor)
intStart = 0
intFinish = 0
Else
If intFinish < 1 Then
intFinish = intButtonPushed
UpdateControls(intStart, intFinish, Color.Red)
Else
If intButtonPushed <= intStart Then
If intFinish > 0 Then
UpdateControls(intStart, intFinish, btnSaveVacation.BackColor)
End If
intStart = intButtonPushed
myButton = Me.Controls("Button" & intButtonPushed.ToString)
myButton.BackColor = Color.Red
Else
intFinish = intButtonPushed
UpdateControls(intStart, intFinish, Color.Red)
If intFinish < intTotalButtonCount Then
UpdateControls(intFinish + 1, intTotalButtonCount, btnSaveVacation.BackColor)
End If
End If
End If
End If
End If
End If
End If
End If
End With
Next i
End Sub
If you'd be willing to have all the rows be the same length (31 days in each row but the last day(s) greyed out for shorter months or something) I think it would be fairly easy to use a standard WinForms DataGridView.
It supports both row and column headers so you could easily add month name and day number if you want.
Just store what cell the first click was in and on the next cell click you change the colour on those two controls and all controls between them.