How to save a Forms Background Image using My.Settings.Save Visual Basic - vb.net

I'm trying to make an Operating System in Visual Basic (program based of course) and it needs personalisation.
I want the user to be able to choose from a select group of images, stored in the Resources of the project, and I want that image to be saved, so that the next time they log on to the software, the form has the same image they selected saved.
Extra Information:
The image selection is on a seperate form. Using:
If ComboBox1.Text = "Beach Fade" Then
PictureBox1.BackgroundImage = My.Resources.beach_fade
End If
Main Desktop form uses the "Background image" to have the image selected.

Use My.Settings to persist user settings.
This is the code I used to demo it. I have a form with ComboBox1 and PictureBox1. With this code, you can have your image selection persist.
Go into your project properties and click the Settings option on the left. Create a setting called BackgroundImageName of type String. You can choose if the scope is saved per-user or per-application.
Then in project properties go to Resources and add two images named "beach_fade" and "mountain_fade". You know how to do this
Then paste this code
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.ComboBox1.Items.Add("Beach Fade")
Me.ComboBox1.Items.Add("Mountain Fade")
Me.ComboBox1.Text = My.Settings.BackgroundImageName
setBackgroundImage()
End Sub
Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
My.Settings.BackgroundImageName = Me.ComboBox1.Text
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
setBackgroundImage()
End Sub
Private Sub setBackgroundImage()
If ComboBox1.Text = "Beach Fade" Then
PictureBox1.BackgroundImage = My.Resources.beach_fade
ElseIf ComboBox1.Text = "Mountain Fade" Then
PictureBox1.BackgroundImage = My.Resources.mountain_fade
End If
End Sub
End Class
The application will start up every time with the image selected in the ComboBox before last close.

Related

CrystalReportViewer.RefreshReport hangs when running from BackgroundWorker

I'm trying to "enhance" my reporting code by adding a loading screen while the Crystal Report is being prepared/loaded. Before I started trying to add the loading screen, all of my reports would come up just fine, but the cursor change just wasn't "enough" of an indication that the application was still working on pulling the report - some of them can take a while - so I wanted to provide a more "obvious" visual cue.
In order to accomplish this, I've put the report creation method calls into a BackgroundWorker that exists in the loading screen itself (I haven't gotten around to learning how to use Async/Await well enough yet to feel comfortable using that instead). The loading screen comes up correctly and everything appears to work as expected until it actually attempts to display the report on screen. At that point, the "Please wait while the document is processing." box comes up (in the CrystalReportViewer control in the form used to display reports), but it just sits there, not even spinning. Eventually, my IDE throws an error about receiving a ContextSwitchDeadlock and I pretty much just have to cancel execution.
Here's my dlgReportLoading "splash screen" with a PictureBox control that contains an animated GIF:
Imports System.Windows.Forms
Public Class dlgReportLoading
Private DisplayReport As Common.CRReport
Private WithEvents LoadReportWorker As System.ComponentModel.BackgroundWorker
Public Sub New(ByRef Report As Common.CRReport)
InitializeComponent()
DisplayReport = Report
End Sub
Private Sub dlgReportLoading_Load(sender As Object, e As EventArgs) Handles Me.Load
Me.Cursor = Cursors.WaitCursor
Me.TopMost = True
Me.TopMost = False
LoadReportWorker = New System.ComponentModel.BackgroundWorker
LoadReportWorker.RunWorkerAsync()
End Sub
Private Sub dlgReportLoading_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
Me.Cursor = Cursors.Default
End Sub
Private Sub LoadReport_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles LoadReportWorker.DoWork
If Not DisplayReport.ReportOption = Common.CRReport.GenerateReportOption.None Then
Select Case DisplayReport.ReportOption
Case Common.CRReport.GenerateReportOption.DisplayOnScreen
'-- This is the method I'm currently testing
DisplayReport.ShowReport()
Case Common.CRReport.GenerateReportOption.SendToPrinter
DisplayReport.PrintReport()
Case Common.CRReport.GenerateReportOption.ExportToFile
DisplayReport.ExportReport()
End Select
End If
DisplayReport.ReportOption = Common.CRReport.GenerateReportOption.None
'--
'-- This code was in use before trying to generate the reports in the background
'If Not DisplayReport.CrystalReport Is Nothing Then
' DisplayReport.CrystalReport.Dispose()
'End If
'--
End Sub
Private Sub LoadReport_Complete(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles LoadReportWorker.RunWorkerCompleted
Me.DialogResult = DialogResult.OK
Me.Close()
End Sub
End Class
As noted in the code above, I'm currently testing the ShowReport() method as defined here:
Protected Friend Sub ShowReport()
Dim ReportViewer As frmReportPreview
Me.PrepareReport()
ReportViewer = New frmReportPreview(Me)
With ReportViewer
.WindowState = FormWindowState.Maximized
.Show()
End With
End Sub
And the frmReportPreview is this:
Imports System.ComponentModel
Public Class frmReportPreview
Private DisplayReport As Common.CRReport
Private ReportToDisplay As CrystalDecisions.CrystalReports.Engine.ReportDocument
Public Sub New(ByRef Report As Common.CRReport)
InitializeComponent()
DisplayReport = Report
PrepareReportForDisplay()
Me.rptViewer.ReportSource = Nothing
Me.rptViewer.ReportSource = ReportToDisplay
' SET ZOOM LEVEL FOR DISPLAY:
' 1 = Page Width
' 2 = Whole Page
' 25-100 = zoom %
Me.rptViewer.Zoom(1)
Me.rptViewer.Show()
End Sub
Private Sub frmReportPreview_Shown(sender As Object, e As EventArgs) Handles Me.Shown
'-- HANGS HERE
Me.rptViewer.RefreshReport()
End Sub
Private Sub frmReportPreview_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
ReportToDisplay.Dispose()
Me.rptViewer.ReportSource = Nothing
End Sub
'...CODE FOR PREPARING THE REPORT TO BE DISPLAYED
End Class
The dlgReportLoading form pops up correctly and the animation plays until the frmReportPreview pops up in front of it (it doesn't close). The little box that has what is normally an animated spinning circle indicating the report data is being loaded appears, but almost immediately freezes in place.
I have a breakpoint in the LoadReport_DoWork() method of my dlgReportLoading form after the call to the ShowReport() method, but it never gets to that point. I also have one in the LoadReport_Complete() method of that form that it never hits either and that dialog never actually closes.
I put another breakpoint at the end of the frmReportPreview_Shown method, right after the Me.rptViewer.RefreshReport() call, but it never hits that either, so it seems clear that this is where things are getting stuck, but only when the report is being generated through the BackgroundWorker. If I just call the ShowReport() method without sending it through the "splash screen" and BackgroundWorker, everything generates and displays normally.
I've tried putting the RefreshReport() method into its own BackgroundWorker with no change in the behavior. I've tried making the frmReportPreview object display modally with ShowDialog() instead of just Show(). None of this seems to help the issue.
I have a feeling something is being disposed of too early somewhere, but I can't figure out what that would be. I can provide the rest of the report preparation code from frmReportPreview if required, but that all seems to be working without error, as far as I can tell. I'm not averse to trying alternate methods of accomplishing my goal of showing the user a loading screen while all the report preparation is taking place - e.g., Async/Await or other multi-threading methods - so any suggestions are welcome. Please let me know if any additional clarification is needed.
ENVIRONMENT
Microsoft Windows 10 Pro 21H1 (OS build 19043.1348)
Microsoft Visual Studio Community 2017 (v15.9.38)
Crystal Reports for .NET Framework v13.0.3500.0 (Runtime version 2.0.50727)
EDIT: I forgot to mention that this whole mess is being called from a GenerateReport() method in my CRReport class defined as:
Public Sub GenerateReport(ByVal ReportGeneration As GenerateReportOption)
Me.ReportOption = ReportGeneration
If Me.ReportOption = GenerateReportOption.None Then
'...CODE FOR REQUESTING A GENERATION OPTION FROM THE USER
End If
Dim ReportLoadingScreen As New dlgReportLoading(Me)
ReportLoadingScreen.ShowDialog()
End Sub
Which, in turn, is being called from my main form like this:
Private Sub PrintMyXMLReport(ByVal XMLFile As IO.FileInfo)
Dim MyXMLReport As New IO.FileInfo("\\SERVER\Applications\Reports\MyXMLReport.rpt")
Dim Report As New Common.CRReport(MyXMLReport, XMLFile)
Report.GenerateReport(Common.CRReport.GenerateReportOption.DisplayOnScreen)
End Sub
You should separate the heavy lifting and UI operations into distinct methods in order to put them into the appropriate BackgroundWorker events:
Protected Friend Sub PrepareReport()
' perform long-running background work
End Sub
Protected Friend Sub ShowReport()
Dim ReportViewer = New frmReportPreview(Me) With {.WindowState = FormWindowState.Maximized}
ReportViewer.Show()
End Sub
Private DisplayReport As Common.CRReport
Private Sub LoadReport_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles LoadReportWorker.DoWork
DisplayReport.PrepareReport()
End Sub
Private Sub LoadReport_Complete(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles LoadReportWorker.RunWorkerCompleted
DisplayReport.ShowReport()
Me.DialogResult = DialogResult.OK
Me.Close()
End Sub
because LoadReport_DoWork actually runs on a new non-UI thread, and LoadReport_Complete runs on the caller thread, which is a UI thread. Only there can you interact with the UI and show Forms etc.

Theme changed event?

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

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.

combox selected index didnt work on picturebox

Now what i was doing is when i click a button group box 1 and group box 2 will show out i want to select the combobox item than the picturebox item will load
and this can be used it multiple time like when button-5 clicked the combobox item name will change and the picture will change too.
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
GroupBox1.Show()
GroupBox2.Show()
comboboxselectdiffrent.Items.Add("pizza_ChickenSupreme")
comboboxselectdiffrent.Items.Add("pizza_CockadoodleBacon")
If comboboxselectdiffrent.SelectedIndex = 0 Then
PictureBox1.Image = PIZZA_HUT_SYSTEM_NEW_VER.My.Resources.Resources.pizza_ChickenSupreme
ElseIf comboboxselectdiffrent.SelectedIndex = 1 Then
PictureBox1.Image = PIZZA_HUT_SYSTEM_NEW_VER.My.Resources.Resources.pizza_CockadoodleBacon
End If
End Sub
Can anyone tell me what i was do wrong? i have no idea why it wont work
After looking at your code personality I would have the event trigger from the combobox click, that way it will save the user having to first click on the combo to select their pizza and then having to click on a button to load the picture & details. Nevertheless try this.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ComboBox1.Items.Add("pizza_ChickenSupreme")
ComboBox1.Items.Add("pizza_CockadoodleBacon")
ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
GroupBox1.Show()
GroupBox2.Show()
Select Case ComboBox1.SelectedItem
Case Is = "pizza_ChickenSupreme"
PictureBox1.ImageLocation = "Pictures/mypic.jpg"
Case Is = "pizza_CockadoodleBacon"
PictureBox1.ImageLocation = "Pictures/mypic1.jpg"
End Select
End Sub
End Class
Using a custom Folder within the solution explorer will be better than using a setting resource. Create a folder and drag your pictures into it and change the name of the image location to suit your needs.
Also i think using the items name is better than the items index because what happens if someone reason that indexed item is to change from 1 to 5, you would have to recode it all, but by using the items name, it has more detail as to what to look for.
If you have any problems, leave a comment and I will do my best to help you out.Happy Coding!

Drag and drop an image into a RichTextBox

I am updating code done in VB 4, where I have a RichTextBox. I need to be able to drag-and-drop an image from Windows Explorer into the RTB. Unfortunately, I am unable to get the drag-and-drop to work.
I've created a much more simple Windows Form program to try to resolve this, but have made no progress. I begin by setting AllowDrop to True.
Public Sub New()
InitializeComponent()
Me.DragAndDropTextBox.AllowDrop = True
End Sub
I then create handlers for the RTB. These are taken directly from MSDN.
Private Sub DragAndDropTextBox_DragEnter(ByVal sender As Object, ByVal e As _
System.Windows.Forms.DragEventArgs) Handles DragAndDropTextBox.DragEnter
' Check the format of the data being dropped.
If (e.Data.GetDataPresent(DataFormats.FileDrop)) Then
' Display the copy cursor.
e.Effect = DragDropEffects.Copy
Else
' Display the no-drop cursor.
e.Effect = DragDropEffects.None
End If
End Sub
Private Sub DragAndDropTextBox_DragDrop(ByVal sender As Object, ByVal e As _
System.Windows.Forms.DragEventArgs) Handles DragAndDropTextBox.DragDrop
System.Windows.Forms.DragEventArgs) Handles DragAndDropTextBox.DragDrop
Dim img As Image
img = Image.FromFile(e.Data.GetData(DataFormats.FileDrop, False))
Clipboard.SetImage(img)
Me.DragAndDropTextBox.SelectionStart = 0
Me.DragAndDropTextBox.Paste()
End Sub
When I grab an image in Explorer and drag it over my window, I get the circle with a slash. I have put breakpoints on the first line of each of the handlers, and they are never reached. I have looked at several pages, and they all seem to give the same process, so I must be missing something simple.
I am not worried right now about pasting the image into the text box; I know I need to work on that. I am only trying to capture the image, but the handler methods do not seem to be getting called.
UPDATE
After quite a bit of experimentation, I found that the actual issue is with my Visual Studio 2010, which I always run as administrator. When I run the program from an exe, the drag-and-drop works. When I try running from VS in debug, it does not. Has anyone experienced this before?
If anyone could shed some light on this, I would be very grateful.
Try getting rid of the InitializeComponent() call in your Sub New function. When I did that, I was able to detect the DragEnter event. Here is the code I tested (I created a simple WinForm and put a RichTextBox on it called DragAndDropTextBox):
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
DragAndDropTextBox.AllowDrop = True
End Sub
Private Sub DragAndDropTextBox_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DragAndDropTextBox.DragEnter
Debug.Print("Entering text box region")
' Check the format of the data being dropped.
If (e.Data.GetDataPresent(DataFormats.FileDrop)) Then
' Display the copy cursor.
e.Effect = DragDropEffects.Copy
Else
' Display the no-drop cursor.
e.Effect = DragDropEffects.None
End If
End Sub
Private Sub DragAndDropTextBox_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DragAndDropTextBox.DragDrop
Dim img As Image
img = Image.FromFile(e.Data.GetData(DataFormats.FileDrop, False))
Clipboard.SetImage(img)
Me.DragAndDropTextBox.SelectionStart = 0
Me.DragAndDropTextBox.Paste()
End Sub
End Class
The InitializeComponent() call should appear in your code (I believe) when you add your own custom controls to a form. Otherwise, I don't think you need to call it.
It turned out that the Drag-And-Drop was working when running the code from an exe, but not from within Visual Studio. More searching turned up this answer, which states that Drag-And-Drop does not work in Visual Studio when it is run as an Administrator. I ran it with normal permissions, and the code worked.