Theme changed event? - vb.net

Ive built a Winforms RadForms application with VB.Net. The application contains several forms that contains several rad controls. The theme is changed by clicking a button. But it takes around 3-4 seconds for the theme to change. Now what I want to achieve is the application must show a message box with the message- "Theme Changed" when the theme has changed. I was wondering if there are any events that can be fired during a theme change and found one event named "ThemeNameChanged". I set it up like this:
Private Sub theme_changed (source as Object, args As ThemeNameChangedEventArgs) Handles Me.ThemeNameChanged
Msgbox("Theme Changed")
End Sub
Then I switch the theme with the click of a button:
Private sub Button1_Click(...) Handles Button1.Click ThemeResolutionService.ApplicationThemeName = "TelerikMetroBlue"
End Sub
But when click Button1 the theme changes but the message is not displayed once the theme has changed. So How Do I dsiplay a message when the theme has changed?

Setting the ThemeResolutionService.ApplicationThemeName property will style the entire application with the newly applied theme. However, in order to detect the theme changing in this case the ThemeResolutionService offers the ApplicationThemeChanged event:
Sub New()
InitializeComponent()
AddHandler ThemeResolutionService.ApplicationThemeChanged, AddressOf ThemeResolutionService_ApplicationThemeChanged
End Sub
Private Sub RadButton1_Click(sender As Object, e As EventArgs) Handles RadButton1.Click
ThemeResolutionService.ApplicationThemeName = "Fluent"
End Sub
Private Sub RadButton2_Click(sender As Object, e As EventArgs) Handles RadButton2.Click
ThemeResolutionService.ApplicationThemeName = "FluentDark"
End Sub
Private Sub ThemeResolutionService_ApplicationThemeChanged(sender As Object, args As ThemeChangedEventArgs)
RadMessageBox.Show("Theme changed " & ThemeResolutionService.ApplicationThemeName)
End Sub

Related

Improve UI responsiveness on windows form application

I am currently working on a project and decided to create a user interface for it using visual studio with a windows forms application(Visual Basic).
The problem I'm facing is that the user interface doesn't respond as quickly and smoothly as I'd like it to.
Mainly, I am using pictures as buttons to make the user form look more modern.
However, when I hover my mouse over a "button" it takes a while until the "highlighted button" appears.
P1 is the picture of the "normal button" and P2 is the picture of the "highlighted button".
Here is the short code I have for now:
Public Class Main
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub PictureBox1_MouseHover(sender As Object, e As EventArgs) Handles P1.MouseHover
P1.Visible = False
P2.Visible = True
End Sub
Private Sub P2_MouseClick(sender As Object, e As MouseEventArgs) Handles P2.MouseClick
'Call cmdInit()
'Call cmdConnectRobot()
'Call cmdUnlock()
End Sub
Private Sub Main_MouseHover(sender As Object, e As EventArgs) Handles Me.MouseHover
If P2.Visible = True Then
P2.Visible = False
P1.Visible = True
End If
End Sub
Private Sub P4_Click(sender As Object, e As EventArgs) Handles P4.Click
End Sub
End Class
Another problem I'm facing is that when I call other subs, the user form becomes unresponsive while the sub is running.
I researched and found that I could implement multi threading or async tasks but I'm a bit lost and would be extremely grateful if someone could guide me or point me in the right direction.
Thanks in advance!!
In this case your UI is responsive, however the MouseHover event is only raised once the mouse cursor has hovered over the control for a certain amount of time (default is 400 ms), which is what is causing the delay.
What you are looking for is the MouseEnter event, which is raised as soon as the cursor enters ("touches") the control:
Private Sub P1_MouseEnter(sender As Object, e As EventArgs) Handles P1.MouseEnter
P1.Visible = False
P2.Visible = True
End Sub
You can then use that together with the MouseLeave event on the second picture box to switch back to the non-highlighted image:
Private Sub P2_MouseLeave(sender As Object, e As EventArgs) Handles P2.MouseLeave
P1.Visible = True
P2.Visible = False
End Sub
However switching picture boxes like this is not optimal. I recommend you to look into how you can use Application Resources, then modify your code to only switch the image that one picture box displays.
Here are the basic steps:
Right-click your project in the Solution Explorer and press Properties.
Select the Resources tab.
To add an image either:
a. Drag and drop the image onto the resource pane.
b. Click the arrow next to the Add Resource... button and press Add Existing File....
Now, in your code add this right below Public Class Form1:
Dim ButtonNormal As Image = My.Resources.<first image name>
Dim ButtonHighlighted As Image = My.Resources.<second image name>
Replace <first image name> and <second image name> with the names of your button images.
Now you only need one picture box for the button:
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
P1.Image = ButtonNormal
End Sub
Private Sub P1_MouseEnter(sender As System.Object, e As System.EventArgs) Handles P1.MouseEnter
P1.Image = ButtonHighlighted
End Sub
Private Sub P1_MouseLeave(sender As System.Object, e As System.EventArgs) Handles P1.MouseLeave
P1.Image = ButtonNormal
End Sub
I'll start by saying i'm not a programmer by trade, and i'm sure someone will point out better ways of doing these things, but in regards to the threading question it's fairly simple to implement.
Imports System.Threading
Public Class Form1
Dim WorkerThread As New Thread(AddressOf DoWork)
'WorkerThread' can be any name you like, and 'DoWork' is the name of the sub you want to run in the new thread, and is launched by calling:
WorkerThread.start()
However there is a catch, the new thread is not able to interact directly with the GUI, so you cannot change textbox text etc... I find the easiest way to get changes made to the GUI is to drag a timer onto your form, and have the new thread change variables (pre-defined just below Public Class Form1), then use the Timer1 Tick event to monitor the variables and update the GUI if there are any changes.

Labels' Click events

I have an application where I have around 50 labels. In those labels a number is visible.
When the user clicks on the label the number needs to be written to an edit box.
This works fine, the only problem is that I have added 50 functions like below, and every time it’s the same. I was wondering if there is a common function for this
Remark: The labels have different names. So if its possible that this will work for all the labels on the form.
Private Sub LI_L_Click(sender As Object, e As EventArgs) Handles LI_L.Click
cmbOBJID.Text = LI_L.Text
End Sub
In the form designer, you should be able to set the handler for every label to the same function. Then you can use the "sender" parameter to determine which label is raising the event.
Notice also how all the controls that the function is linked to are listed after the "Handles" keyword. This is another way you could connect the code to all the labels if you prefer this over using the Visual Studio UI properties grid.
Private Sub LI_Click(sender As Object, e As EventArgs) Handles Label1.Click, Label2.Click, Label3.Click
cmdOBJID.Text = DirectCast(sender, Label).Text
End Sub
While it is easy to add several events to one handler in the style of
Private Sub LI_Click(sender As Object, e As EventArgs) Handles Label1.Click, Label2.Click, Label3.Click
It will be tedious for more than just a few labels.
You can add handlers programatically if you can find a way to refer to the labels you need to add handlers to. In this example, I put all the labels in a groupbox named "GroupBoxOptions":
Option Infer On
Option Strict On
Public Class Form1
Sub TransferDataToEditBox(sender As Object, e As EventArgs)
Dim lbl = DirectCast(sender, Label)
tbEditThis.Text = lbl.Text
End Sub
Sub InitLabelHandlers()
For Each lbl In GroupBoxOptions.Controls.OfType(Of Label)
AddHandler lbl.Click, AddressOf TransferDataToEditBox
Next
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitLabelHandlers()
End Sub
End Class
You may have some other way of selecting the labels which use the handler.
A pretty nice and quick solution is to traverse all the label controls on a form, assigning through the AddHandler function the event to run when a user clicks a label.
In code:
For Each c As Control In Me.Controls.OfType(Of Label)
AddHandler c.Click, AddressOf myLabelClick
Next
With the prevous snippet, we loop onto all the winform controls of type Label. A loop like that is useful when we have a lot of labels for which an event must be assigned. For each of them, we associate the event Click of the control with a customized Sub named myLabelClick. That subroutine will look like the following:
Private Sub myLabelClick(sender As Object, e As EventArgs)
cmdObjId.Text = DirectCast(sender, Label).Text
End Sub
Here we use the sender variable (which represents the control for which the click has been done) to access its Text property, and change the cmdObjId.Text accordingly.
Just to complement the solution from BlueMonkMN:
If you are using the DevExpress Tools, you need to import DevExpress.XtraEditors and change Label to LabelControl:
DirectCast(sender, LabelControl).Text
This worked for me.

VB.Net code in class FormClosing error

I've created a VB.Net application which consists of a form and a series of classes. One class (GUI) contains all of the routines that handle the logic associated with the controls on my form. These controls are placed at design time.
My application runs in the system tray so I need to trap the FormClosing event so that the application is minimised rather than closed. Before moving everything into the GUI class my code worked but I'm now getting an error on this line:
Private Sub Monitor_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
which is "Event 'FormClosing' cannot be found"
I'm completely stumped by this. I've changed changing the MyBase parameter to refer to the form by name, leaving it off and also adding:
Private WithEvents Monitor As System.Windows.Forms.Form
but none work.
EDIT: Here's a stripped down version of my GUI class containing the bits that handle minimising and restoring the form to the system tray
Note that there's no reference to the menu bar and menu items but VS doesn't complain about those.
Public Class GUI
' Make form controls accessible to this class (partial list only
' there's a lot of controls)
Private WithEvents tabControl As TabControl
Private WithEvents btn_status_start As Button
Private WithEvents btn_status_stop As Button
Private WithEvents btn_dataSource As Button
' **************************************************************************************
' * *
' * Control form behaviour so that it can be put into and taken from system tray *
' * *
' **************************************************************************************
Private Sub cms_menu_exit_Click(sender As Object, e As EventArgs) Handles cms_menu_exit.Click
' Handles the saving and shutting down of the program
' Save any settings
My.Settings.Save()
' Remove the icon
Monitor.Dispose()
' Finally close the program
Monitor.Close()
End Sub
Private Sub Notify_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles notify.MouseDoubleClick
' Code to restore the program window from the system tray when double clicked
Me.Restore()
End Sub
Private Sub Notify_MouseClick(sender As Object, e As MouseEventArgs) Handles notify.MouseClick
' Code to restore the program window from the system tray when single clicked
Me.Restore()
Monitor.Focus()
End Sub
Private Sub Restore()
If Monitor.WindowState = FormWindowState.Minimized Then
Monitor.WindowState = FormWindowState.Normal
End If
Monitor.Visible = True
End Sub
Private Sub Monitor_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
' Catch the click on the X on the main form and set program to minimise instead
If (e.CloseReason = CloseReason.UserClosing) Then
e.Cancel = True
Monitor.Hide()
End If
End Sub
Private Sub cms_menu_open_Click(sender As Object, e As EventArgs) Handles cms_menu_open.Click
' Maximise the main form if selected
Monitor.Show()
Monitor.Focus()
End Sub
End Class

How can I find the sender of ContextMenuStrip?

Situation:
I have a context menu in a VB.NET form with fires an event handler on ItemClicked. The auto-generated subroutine receives sender and e as parameters. As I don't reinvent the wheel multiple times, I linked this context menu to three text boxes. Let's name them Textbox1, Textbox2 and Textbox3.
Problem: How can I figure out in which textbox the menu was opened?
Okay, what did I already try?
sender contains the menu itself,
e.ClickedItem just returns the single menu item that was selected.
sender.Parent is always nothing
sender.OwnerItem is also always Nothing`
Me.Textbox1.Focused is always False, even if its the "parent" control of the menu.
Okay, I found a solution that works fine, and here's the code for all VB.NET coders that have the same problem.
The context menu is linked in TextBox1, so we need to add another event handler that saves the sending control into the menu:
Private Sub TextBox1_MouseUp(sender As Windows.Forms.Control, e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseUp
If e.Button = Windows.Forms.MouseButtons.Right Then
ContextMenu.Tag = sender
End If
End Sub
And this is the code of the event handler when clicking a menu item:
Private Sub ContextMenu_ItemClicked(sender As System.Object, e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles ContextMenu.ItemClicked
ContextMenu.Close()
If ContextMenu.Tag Is Nothing Then
Debug.Print("debug info: forgot to set sender? well ... KABOOM!")
Exit Sub
End If
Dim oParent As Windows.Forms.Control
Try
oParent = ContextMenu.Tag
Catch ex As Exception
Debug.Print("debug info: tag contains data other than sender control. well ... KABOOM!")
Exit Sub
End Try
' Do fancy stuff here.
' Release sender
ContextMenu.Tag = Nothing
End Sub
The ContextMenuStrip has a SourceControl property which contains a reference to the control which opened the menu. The event fires from one of the ToolStripMenuItems in the ContextMenuStrip, so you have to get the "parent" first:
' cast sender to menuitem
Dim mi = CType(sender, ToolStripMenuItem)
' cast mi.Owner to CMS
Dim cms = CType(mi.Owner, ContextMenuStrip)
' the control which opened the menu:
Console.WriteLine(cms.SourceControl.Name)
Under certain conditions the SourceControl can get lost but you can track it yourself with a variable and the parent ContextMenuStrip Opening event:
' tracking var:
Private MenuSourceControl As Control
Private Sub cms_Opening(sender As Object, e As CancelEventArgs) Handles cms.Opening
' set reference in case/before it is lost
MenuSourceControl = CType(sender, ContextMenuStrip).SourceControl
End Sub
Private Sub CutToolStripMenuItem_Click(sender...
If MenuSourceControl IsNot Nothing Then
' do your stuff
' optionally clear the tracking var
MenuSourceControl = Nothing
End If
End Sub
It should be also easier to get the SourceControl when dealing with sub items
You can also capture the related control in the MouseDown event of the related Control in cases where the same menu is used with different controls:
Private Sub lv2_MouseDown(sender As Object,
e As MouseEventArgs) Handles lv2.MouseDown,
myLV.MouseDown, lv1.MouseDown ...
If e.Button = Windows.Forms.MouseButtons.Right Then
MenuSourceControl = DirectCast(sender, Control)
End If
End Sub

combobox not being populated

I have a windows form project with a main form. There is a textbox leave event that opens a new form. In that new forms load event i have a combobox item loop that populates the combobox items. It works perfectly fine if run on the main form but doesnt work on the second form. Why doesn't the comboboxes on the secondary form populate when that form is opened via a textbox_leave event from the main form?
this is the leave event
Private Sub tbChartTitle_Leave(sender As Object, e As System.EventArgs) Handles tbChartTitle.Leave
If Not tbChartTitle.Text = Nothing Then
frmTitleAttributes.Show()
End If
End Sub
This is the code that populates one of the comboboxes on the second form (it works if run on a combobox on the main form)
Private Sub frmTitleAttributes_Load(sender As Object, e As System.EventArgs) Handles Me.Load
InitializeComponent()
AddFonts()
End Sub
Private Sub AddFonts()
' Get the installed fonts collection.
Dim allFonts As New Drawing.Text.InstalledFontCollection
' Get an array of the system's font familiies.
Dim fontFamilies() As FontFamily = allFonts.Families
' Display the font families.
For i As Integer = 0 To fontFamilies.Length - 1
cbxTitleFonts.Items.Add(fontFamilies(i).Name)
Next
End Sub
make sure that the Load handler is hit after you show your form (use break point)
also you can try to call it in the Shown event
Private Sub frmTitleAttributes_Shown(sender as Object, e as EventArgs) _
Handles frmTitleAttributes.Shown
AddFonts()
End Sub