Dynamically Changing Button Properties

I am writing an application where I have a 5x5 array of buttons that I want to dynamically update some of the properties.

I have created all of the buttons in the editor and have given then names that reference their position in the matrix (i.e. btnGrid11, btnGrid12, etc.). Based on the button that a user presses, I would like to update the image that is shown.

I would like to do this in a loop and the problem that I am running into is that I cannot figure out how to dynamically reference an existing resource. This is an example of what I think the code should look like. I was thinking that I could create a button resource and then give it the name of an existing button and then change the properties. The code compiles and executes but it doesn't work (no image appears for the buttons).

For x = 1To 5
For y = 1To 5
FileName = {
Get data from database query}
btnCurrent.Name =
"btnGrid" +CStr(x) +CStr(y)
bmpIcon = Bitmap.FromFile(
"C:\Bitmaps\" + FileName)
btnCurrent.Image = bmpIcon
btnCurrent.Visible =
True
Next
Next

Any ideas?

[1776 byte] By [Johngeh] at [2007-12-16]
# 1
I put this code into the IDE, and it worked oK.


Button1.Visible = True

Button1.Text = "New Text"

Button1.Name = "New Name"

Button1.Image = Image.FromFile("c:\tmp\pic1.bmp")



It must be how you are referencing your buttons.
Your code shows 2 loops from 1 to 5. Most arrays start at 0.
Are you sure you shouldn't be using

For x = 0 to 4

Dustin_H at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 2
I used this code as well and it worked but that isn't what I am trying to do.

For a 5 x 5 array, I have 25 elements. I would have to create copy and paste your code 25 times changing the name of the button each time. I know that this would work but it doesn't seem terribly efficient to me.

Basically, I want to create a variable name that can be used to represent an existing object and then change the properties on that object during runtime.

Johngeh at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 3
Here's a quick example of creating, and naming 5 buttons, and adding them to a form. (from the form_Load event)



Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim Buttons As Button()

ReDim Buttons(4)

For i As Integer = 0 To Buttons.GetUpperBound(0)

Buttons(i) = New Button

With Buttons(i)

.Name = "New Button" & i

.Text = "Button " & i

.Left = (i * .Width) + 5

End With

Me.Controls.Add(Buttons(i))

Next

End Sub

End Class



Dustin_H at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 4
Sorry, I am obviously not being clear with what I am trying to do here. The buttons already exist.

I am not trying to add them, I simply want to change some of their properties programatically.

John

Johngeh at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 5
OK, i think i get it now Big Smile
You have to enumerate the form's controls, and update from there...
I've added 2 buttons to a form.
It's hard to give a accurate sample without knowing how you are referencing the buttons. (ie, when you click button 2x2, you want button 2x4 to say something else..)



Public Sub UpdateButton(ByVal sName As String, ByVal Text As String)
For Each ctrl As Button In Me.Controls
If ctrl.Name = sName Then
ctrl.Text = Text
Exit Sub
End If
Next
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim x As String
x = "2"
UpdateButton("Button" & x, "Renamed")
End Sub

If this still isn't what you're looking for, you'll have to be more specific or paste some more code to let me know what you're looking for.

Dustin.

Dustin_H at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 6
This wasn't what I was thinking of but it does work. Here is the code that I ended up with in case someone else tries to do something similar...



For Each ctrl As Button In Me.grpHDTV.Controls
If InStr(ctrl.Name, "btnCh") Then
iCol = Mid(ctrl.Name, 6, 1)
iRow = Mid(ctrl.Name, 7, 1)
If iChannels(iCol, iRow) > 0 Then
If File.Exists("{file}") Then
bmpIcon = Bitmap.FromFile("{file}")
ctrl.Image = bmpIcon
Else
ctrl.Text = iChannels(iCol, iRow)
End If
ctrl.Enabled = True
ctrl.Visible = True
End If
End If
Next

Thanks for your help Dustin.

John

Johngeh at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 7

This code worked with Beta 2 but after I upgraded to the July release, it stopped working. Here is the error that I am getting:

System.InvalidCastException was unhandled
Message="Unable to cast object of type 'System.Windows.Forms.GroupBox' to type 'System.Windows.Forms.Button'."
Source="MediaControl"
StackTrace:
at MediaControl.frmInitial.DisplayChannelIcons(String sType, String sParameter) in C:\Documents and Settings\john\My Documents\Visual Studio 2005\Projects\MediaControl\frmInitial.vb:line 1592
at MediaControl.frmInitial.btnHDJohn_Click(Object sender, EventArgs e) in C:\Documents and Settings\john\My Documents\Visual Studio 2005\Projects\MediaControl\frmInitial.vb:line 1583
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at MediaControl.frmInitial.Main() in C:\Documents and Settings\john\My Documents\Visual Studio 2005\Projects\MediaControl\frmInitial.vb:line 10
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Here is my build information:

Microsoft Visual Studio 2005
Version 8.0.50601.0 (lab23dev.050601-0000)
Microsoft .NET Framework
Version 2.0.50601

Installed Edition: Enterprise

Microsoft Visual Basic 2005 55603-000-0000016-00375
Microsoft Visual Basic 2005

Microsoft Visual C# 2005 55603-000-0000016-00375
Microsoft Visual C# 2005

Microsoft Visual C++ 2005 55603-000-0000016-00375
Microsoft Visual C++ 2005

Microsoft Visual Studio Tools for Office 55603-000-0000016-00375
Microsoft Visual Studio Tools for the Microsoft Office System

Microsoft Visual Web Developer 2005 55603-000-0000016-00375
Microsoft Visual Web Developer 2005

Team Edition for Testers 2005 55603-000-0000016-00375
Team Edition for Testers 2005

Visual Studio Team Edition for Software Architects 2005 55603-000-0000016-00375
Visual Studio Team Edition for Software Architects 2005

Crystal Reports for Visual Studio 2005 AAP50-GS00000-U7000RN
Crystal Reports for Visual Studio 2005
Was something changed between beta 2 and the July release that would cause this to happen?

Thanks.

John

Johngeh at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 8

This code worked with Beta 2 but after I upgraded to the July release, it stopped working. Here is the error that I am getting:

System.InvalidCastException was unhandled
Message="Unable to cast object of type 'System.Windows.Forms.GroupBox' to type 'System.Windows.Forms.Button'."
Source="MediaControl"
StackTrace:
at MediaControl.frmInitial.DisplayChannelIcons(String sType, String sParameter) in C:\Documents and Settings\john\My Documents\Visual Studio 2005\Projects\MediaControl\frmInitial.vb:line 1592
at MediaControl.frmInitial.btnHDJohn_Click(Object sender, EventArgs e) in C:\Documents and Settings\john\My Documents\Visual Studio 2005\Projects\MediaControl\frmInitial.vb:line 1583
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at MediaControl.frmInitial.Main() in C:\Documents and Settings\john\My Documents\Visual Studio 2005\Projects\MediaControl\frmInitial.vb:line 10
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Here is my build information:

Microsoft Visual Studio 2005
Version 8.0.50601.0 (lab23dev.050601-0000)
Microsoft .NET Framework
Version 2.0.50601

Installed Edition: Enterprise

Microsoft Visual Basic 2005 55603-000-0000016-00375
Microsoft Visual Basic 2005

Microsoft Visual C# 2005 55603-000-0000016-00375
Microsoft Visual C# 2005

Microsoft Visual C++ 2005 55603-000-0000016-00375
Microsoft Visual C++ 2005

Microsoft Visual Studio Tools for Office 55603-000-0000016-00375
Microsoft Visual Studio Tools for the Microsoft Office System

Microsoft Visual Web Developer 2005 55603-000-0000016-00375
Microsoft Visual Web Developer 2005

Team Edition for Testers 2005 55603-000-0000016-00375
Team Edition for Testers 2005

Visual Studio Team Edition for Software Architects 2005 55603-000-0000016-00375
Visual Studio Team Edition for Software Architects 2005

Crystal Reports for Visual Studio 2005 AAP50-GS00000-U7000RN
Crystal Reports for Visual Studio 2005
Was something changed between beta 2 and the July release that would cause this to happen?

Thanks.

John

Johngeh at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 9
According to the error, Message="Unable to cast object of type 'System.Windows.Forms.GroupBox' to type 'System.Windows.Forms.Button'.", you have a groupbox that the application is trying to convert into a button, and it's failing.
Problem is, the For/Each statement just says 'as button', and it tries to convert the controls to a button. Another way to do it is make your own button array by looping through the controls.
Here's the code you would need.


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each btn As Button In GetButtons(Me)
Next
End Sub
Public Function GetButtons(ByVal Container As ContainerControl) As ArrayList
Dim MyButtons As New ArrayList
For Each ea As Control In Container.Controls
If ea.GetType() Is GetType(Button) Then
MyButtons.Add(ea)
End If
Next
Return MyButtons
End Function


Dustin_H at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 10
Thanks for the code. I gave it a try but it seems to be creating a list of buttons for the form and not for the groupbox that the button is in which is what I need.

Any ideas on how to tell it to create a list of buttons in a specific groupbox?

John

Johngeh at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 11
Well, i assumed your buttons where on the form from which you where calling the code...
In any case...
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each btn As Button In GetButtons(Me)
Next
End Sub

the function i used GetButtons(Me) will return all the buttons from the control that you pass it. In my code example, i pass Me, which is the form itself.
Because the function will accept any ContainerControl, you can simply pass it your groupbox instead. IE....
For Each btn As Button In GetButtons(Form1.GroupBox1)
Next


Dustin.
Dustin_H at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 12
I thought that would work as well but I am getting a compiler error:

Error 1 Value of type 'System.Windows.Forms.GroupBox' cannot be converted to 'System.Windows.Forms.ContainerControl'.

Is this a bug?

Johngeh at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 13
That is very strange, considering a groupbox is a container control.. I would say that is a bug!

In any case, when i tried it, i changed ....
Public Function GetButtons(ByVal Container As ContainerControl) As ArrayList
To
Public Function GetButtons(ByVal Container As GroupBox) As ArrayList
Instead of ContainerControl, i pass Groupbox.
This isn't a big problem, but you may have to overload the function to accept a form and a groupbox.
Dustin.

Dustin_H at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 14
That did it! Thanks!!
Johngeh at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...