Dispose dynamic created Controls (Labels) in a quick way - vb.net

i have a lot of dynamic created Labels in a Windows Form, nearly 30 x 80 pieces.
The disposing of this controls works very slow. It takes nearly 1 second where I can see it work step to step.
I use the following code (to dispose all the controls, where the Name starts with "var":
For i As Integer = dlg_main.Controls.Count - 1 To 0 Step -1
If LCase(Left(dlg_main.Controls(i).Name, 3)) = "var"
dlg_main.Controls(i).Dispose()
End If
Next
Is the a quicklier way to dispose the controls?

One option would be to put the labels in a panel then Dispose the panel.
Panel1.Dispose()

problem is solved, see how to declare and to initialize:
Module mdl_main
Private pn1 As System.Windows.Forms.Panel
Public Sub ShowPanelAgain()
pn1 = New System.Windows.Forms.Panel
pn1.Name = "dynPanel1"
dlg_Main.Controls.Add(pn1)
pn1.AutoSize = True
pn1.AutoScroll = True
End Sub
Sub PanelLöschen()
Try
If pn1.IsDisposed = False Then
pn1.Dispose()
dlg_Main.Text = "pn gelöscht"
End If
Catch ex As Exception
MsgBox("Fehler: " & ex.Message)
End Try
End Sub

Related

Why is my invoke adding 10 seconds onto grid loading time?

I've attempted to add a method invoker to stop my error log being spammed with "Bounds cannot be changed while locked."
This has solved my issue, however...It has added an extra 10 seconds onto the loading time of my RadGridView.
I looked at https://www.telerik.com/forums/bounds-cannot-be-changed-while-locked to setup my invoker but there isn't much else that I can see to help with my issue.
I've attached a sample of my code below, any help would be appreciated.
Private Sub bgw_initialLoad_DoWork(sender As Object, e As DoWorkEventArgs)
Try
liveDS = New DataSet
Dim dsholder As DataSet = GetDataFromSQL("LoadData")
Dim dt1 As DataTable = dsholder.Tables(0)
Dim dt_1 As DataTable = dt1.Copy()
dt_1.TableName = "Customer"
liveDS.Tables.Add(dt_1)
Dim dt2 As DataTable = dsholder.Tables(1)
Dim dt_2 As DataTable = dt2.Copy()
dt_2.TableName = "Orders"
liveDS.Tables.Add(dt_2)
Dim dt3 As DataTable = dsholder.Tables(2)
Dim dt_3 As DataTable = dt3.Copy()
dt_3.TableName = "OrderLine"
liveDS.Tables.Add(dt_3)
If RadGridView.InvokeRequired Then
RadGridView.Invoke(New MethodInvoker(AddressOf SetupDataSources))
Else
SetupDataSources()
End If
Catch ex As Exception
sendCaughtError(ex)
End Try
End Sub
Private Sub SetupDataSources()
If liveDS.Tables.Count > 1 Then
RadGridView.DataSource = liveDS.Tables("Customer")
liveOrdersTemplate.DataSource = liveDS.Tables("Orders")
liveOrdersTemplate2.DataSource = liveDS.Tables("OrderLine")
End If
End Sub
Private Sub bgw_initialLoad_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
Try
RadGridView.DataSource = liveDS.Tables("Customer")
Dim template As New GridViewTemplate()
template.DataSource = liveDS.Tables("Orders")
RadGridView.MasterTemplate.Templates.Add(template)
Dim template2 As New GridViewTemplate()
template2.DataSource = liveDS.Tables("OrderLine")
RadGridView.Templates(0).Templates.Add(template2)
Dim relation As New GridViewRelation(RadGridView.MasterTemplate)
relation.ChildTemplate = template
relation.ParentColumnNames.Add("Invoice Customer")
relation.ChildColumnNames.Add("InvoiceCode")
RadGridView.Relations.Add(relation)
Dim relation2 As New GridViewRelation(RadGridView.Templates(0))
relation2.ChildTemplate = template2
relation2.ParentColumnNames.Add("OrderNo")
relation2.ChildColumnNames.Add("OrderNo")
RadGridView.Relations.Add(relation2)
FormatGrid()
SplitContainer2.Panel1.Enabled = True
SplitContainer1.Panel2.Enabled = True
refreshMainGrid()
HideLoadingGif()
Catch ex As Exception
sendCaughtError(ex)
End Try
End Sub
Debugging threads can be hard, trust me. This isn't a "real" answer, but a bunch of tips which may help - which is what I hope will happen.
There are dedicated windows in the debug menu which may help. I started with this webpage when I was wondering what was happening to my application and why it wasn't obvious why it was happening.
Also, while your parallel thread is running, it may "silent crash" if your IDE isn't set to pause on every crash, in which case it won't return a value but will just stay silent. Make sure at least these options are set:
And don't forget to show this window while debugging: (previous image showed Threads and Call stack instead, while they are good to have around while debugging it's the parallel stacks which I was going for)
One last thing: such a big delay may be database related. I'm not saying that it is, but you should be aware of the possibility.
Now the following isn't part of the answer per se, but is more of a friendly advice: put your invoke logic in SetupDataSources() instead, this way wherever it's called you'll be thread safe. Like this:
Private Sub SetupDataSources()
If RadGridView.InvokeRequired Then
RadGridView.Invoke(Sub() SetupDataSources())
End If
If liveDS.Tables.Count > 1 Then
RadGridView.DataSource = liveDS.Tables("Customer")
liveOrdersTemplate.DataSource = liveDS.Tables("Orders")
liveOrdersTemplate2.DataSource = liveDS.Tables("OrderLine")
End If
End Sub
Best of luck... you might need some ;)

Change the visibility of a panel (Windows Forms)

I leave it to you because I can't find a solution to my problem : /
Let me explain, when I press a button I display a panel containing other buttons, at the click of one of the buttons on the panel it should launch a method that will convert the selected files to pdf. As soon as the user has clicked on one of the buttons and confirmed the choice of file, I make my panel invisible and I then launch the conversion method.
The problem is that my panel disappears let's say by half (not entirely) because it launches the conversion method as quickly. I told myself that I was going to go through a secondary thread, however I cannot modify graphic elements on the second thread.
There is my code :
Private Sub PBFolder_Click(sender As Object, e As EventArgs) Handles PBFolder.Click
Try
Insert2Db("Debut de la fonction BTransforme_Click " + Environment.UserName.ToString, 1, 0, "ConvertFiles2PDF")
'Log("Debut de la fonction BTransforme_Click")
Dim OFD As New FolderBrowserDialog
If OFD.ShowDialog = Windows.Forms.DialogResult.OK Then
PanFileFolder.Visible = False
ConvertFileFolder(False, OFD.SelectedPath.ToString)
End If
Catch ex As Exception
'Log("Error " + ex.Message)
Insert2Db("Error " + ex.Message + "User : " + Environment.UserName.ToString, 0, 3, "ConvertFiles2PDF")
Finally
Insert2Db("function BTransforme_Click Terminé " + Environment.UserName.ToString, 1, 0, "ConvertFiles2PDF")
'Log("function BTransforme_Click Terminé")
End Try
LAppOne.Visible = True
GifLoad.Visible = False
Button1.Enabled = True
BLog.Enabled = True
End Sub
As you can see I hide my panel thanks to line: PanFileFolder.Visible = False then I launch my conversion method convertFileFolder (False, OFD.SelectedPath.ToString)
I have put 2 images to illustrate my problem.
the 1st image shows you the panel that appears on click:
the second image shows you the problem that this causes me to choose the folder:
When it has finished converting the files, the panel disappears correctly at this time.
Do you have an idea to solve this problem thank you in advance ;)
I told myself that I was going to go through a secondary thread,
however I cannot modify graphic elements on the second thread.
That is exactly what will fix your problem; ConvertFileFolder() needs to be running in a different thread so that GUI can refresh itself and be responsive to user interact. You can update the GUI from that secondary thread using Invoke() calls.
Here I've added Async to the Button click handler, then we Await the ConvertFileFolder() FUNCTION, which now returns a Task:
Private Async Sub PBFolder_Click(sender As Object, e As EventArgs) Handles PBFolder.Click
' ... other code ...
Using OFD As New FolderBrowserDialog
If OFD.ShowDialog = DialogResult.OK Then
PanFileFolder.Visible = False
Await ConvertFileFolder(False, OFD.SelectedPath.ToString)
End If
End Using
' ... other code ...
End Sub
Public Function ConvertFileFolder(ByVal someFlag As Boolean, ByVal someString As String) As Task
Return Task.Run(Sub()
' ... long running code in here ...
For i As Integer = 1 To 10
System.Threading.Thread.Sleep(1000) ' some "work"
' whenever you need to update the GUI, use Invoke()
Dim value As String = i.ToString
Me.Invoke(Sub()
Label1.Text = value
End Sub)
Next
End Sub)
End Function

Task is running and cannot be finished

Have strange behaviour in my task which is not finishing. I use this all the time but i suppose its because sub i am passing to it is iteracting with form - changing selection and refreshing some listbox probably therefore its stack there but i am not sure. Lets see the code:
This is the sub i want to be run in task:
Public Sub UnselectExistingConnectionsItems()
Dim SentenceId, SubSubKategorieId, SubSectionId As Integer
SubSectionId = CbSubSections.SelectedValue 'combobox
If WithSubSubkategorie = SubSubKategorieEnum.Without Then
SubSubKategorieId = 0
Else
SubSubKategorieId = CbSubSubKategorie.SelectedValue 'combobox
End If
Unselect:
For i As Integer = 0 To LB_Sentences.SelectedItems.Count - 1
Dim sKey As ListBoxItem
sKey = LB_Sentences.SelectedItems(i)
SentenceId = HtmlDescription.HtmlSentence.GetSentenceIdByName(sKey.Text)
If HtmlDescription.HtmlSubSubSections_Sentences.CheckIfConnectionAlreadyExist(SentenceId, SubSectionId, SubSubKategorieId) Then
sKey.IsSelected = False
LB_Sentences.Refresh()
GoTo Unselect
End If
Next
End Sub
i put it to Task like this:
Dim pic As New FrmCircularProgress(eCircularProgressType.Line)
Dim work As Task = Task.Factory.StartNew(Sub()
'--Run lenghty task UnselectExistingConnectionsItems()
'--Close form once done (on GUI thread)
pic.Invoke(New Action(Sub() pic.StopCircular()))
pic.Invoke(New Action(Sub() pic.Close()))
End Sub)
'--Show the form
pic.ShowDialog()
Task.WaitAll(work)
and FrmCircularProgress is just form ( i use it almost everywhere where i have to user wait and its working besides this particural case):
Public Class FrmCircularProgress
Sub New(progressType As DevComponents.DotNetBar.eCircularProgressType)
InitializeComponent()
CircularProgress1.ProgressBarType = progressType
StartCircular()
End Sub
Public Sub StartCircular()
Me.CircularProgress1.IsRunning = True
End Sub
Public Sub StopCircular()
Me.CircularProgress1.IsRunning = False
End Sub
End Class
what could be wrong? is it because procedure is interacting with listbox and combobxes? If so how to fix that, i read something about invoking listbox and comboboxes but have no idea how to fix that.
EDIT:
I think besides those lines:
sKey.IsSelected = False
LB_Sentences.Refresh()
I have to make those:
LB_Sentences.Invoke(Sub() sKey.IsSelected = False
End Sub)
LB_Sentences.Invoke(Sub() LB_Sentences.Refresh()
End Sub)
because i am in diffrent thread. Somehow i dont know how to convert those lines:
SubSectionId = CbSubSections.SelectedValue
SubSubKategorieId = CbSubSubKategorie.SelectedValue
probably loop also have to be invoked. Waiting your help.
There is a rule that says "The only thread that can modify a control in a window is the thread that created the window". Any other thread trying to modify something in the window will generate a cross-thread call exception.
So in your first edit you got it right, you have to invoke the functions.
However, this doesn't fix your problem of not finishing Task.
I believe that doing sKey.IsSelected = False does not unselect anything in your ListBox, therefore causing an infinite loop... Also that Goto statement is very bad programming habits and should not be used. There is always another solution that will make your code easier to debug/maintain/read...
ListBoxItem is not a type that exists in the .Net Framework. So either you created that class either it's something else (and I don't know what...)
What you can do to solve your problem is :
Get the indices of all selected items in a list
Run through your list, and check if they should be selected :
If they should be selected, do nothing
if they shouldn't, unselect them.
Which makes your code like this (and you remove that ugly Label and Goto that you don't want in your code)...
Public Sub UnselectExistingConnectionsItems()
Dim SentenceId, SubSubKategorieId, SubSectionId As Integer
SubSectionId = CbSubSections.SelectedValue 'combobox
If WithSubSubkategorie = SubSubKategorieEnum.Without Then
SubSubKategorieId = 0
Else
SubSubKategorieId = CbSubSubKategorie.SelectedValue 'combobox
End If
'We create an array to remind our initial selection
Dim sel = New Integer(LB_Sentences.SelectedItems.Count - 1) {}
LB_Sentences.SelectedIndices.CopyTo(sel, 0)
For i = 0 To sel.Length - 1
Dim sKey As ListBoxItem
'We get our selected item
sKey = LB_Sentences(sel(i))
SentenceId = HtmlDescription.HtmlSentence.GetSentenceIdByName(sKey.Text)
If HtmlDescription.HtmlSubSubSections_Sentences.CheckIfConnectionAlreadyExist(SentenceId, SubSectionId, SubSubKategorieId) Then
'We must remove it from the selection
LB_Sentences.Invoke(Sub() LB_Sentences.SelectedItems.Remove(sKey))
End If
Next
'We do the Refresh at the end so we gain some process time...
LB_Sentences.Invoke(Sub() LB_Sentences.Refresh())
End Sub

Why is my event handler firing two times?

I have a bunch of panels that I am adding to a single parent panel and I want to add event listeners to all of the panels but not until after they have all been added to the parent (becuase I don't want the event listeners firing each time a new panel gets added). So I am using the following code:
Dim temp_object As question_bar = Nothing
For Each q As Object In review_holder.Controls
If TypeOf q Is question_bar Then
temp_object = q
AddHandler temp_object.Resize, AddressOf temp_object.resize_me
End If
Next
For Each q As Object In review_holder.Controls
If TypeOf q Is question_bar Then
temp_object = q
temp_object.resize_me()
End If
Next
But I noticed that the resize_me() subroutine is getting fired twice for each control. I only want it to fire once. So I traced it out using this code
MsgBox((New System.Diagnostics.StackTrace).GetFrame(1).GetMethod.Name)
and I see that each time it gets called the calling methods are both this subroutine and _Lambda$_365. What the heck is that? How do I find out where that is coming from?
BTW, this is a winforms app using VS2012.
EDIT ------------------------------------------------------------------------
Public Sub resize_me()
MsgBox((New System.Diagnostics.StackTrace).GetFrame(1).GetMethod.Name)
If Me.minimized = True Then
Me.Height = 0
Exit Sub
End If
number_panel.Width = my_parent.number_width
number_text.Width = my_parent.number_width
number_separator.Left = number_panel.Right
question_panel.Left = number_separator.Right
question_panel.Width = question_panel.Parent.Width * initial_question_width + (question_padding * 2)
End Sub
Well changing size properties when you are inside a resize event could explain why your code is recalled again a second time. Usually I try to avoid this kind of situations but this is not always possible. In these cases then a global variable that acts as a flag to block the reentry could save the day
Dim insideResize As Boolean
Public Sub resize_me()
if insideResize = True Then
Exit Sub
End if
insideResize = True
Try
If Me.minimized = True Then
Me.Height = 0
Exit Sub
End If
number_panel.Width = my_parent.number_width
number_text.Width = my_parent.number_width
number_separator.Left = number_panel.Right
question_panel.Left = number_separator.Right
question_panel.Width = question_panel.Parent.Width * initial_question_width + (question_padding * 2)
Finally
insideResize = False
End Try
End Sub
To stay on the safe side with this patterns remember to always use a Try/Finally block to be sure that when you exit from the Resize event the global flag is correctly set back to false.

Picturebox location change 20 times per second not redrawing

I'm trying to make a few images do the nice slidey thingy that I've seen lots of Microsoft applications use. The one where the movement starts slow speeds up half way there and then comes to a nice slow stop in it's new location. I've got all the calculations figured out, getting and setting the picture box locations, Confirmation using console.writeline that the image locations are correct, and even a test run that works in a simplified format.
But in the full blown version It's not repainting the image. In fact, it looks like nothing has happened at all while the script is running. I've tried Me.Refresh(), Invalidate(), Timer.Enabled = True/False, and Me.Update(). None of which have worked. The last step is the most frustrating: I'm calling my SetPanelLocation() method at the end to ensure that the panel ends up in the final location regardless of if the movement worked. Nothing happens on this call either, even though immediately after this routine fails I can call the same method from another user event and it starts working again like nothing was wrong.
I'm creating my own PictureBox class called clsFeedImageBox which inherits PictureBox that includes this functionality (along with other features). Each image is only 300x225 pixels so they're not massive images that take a lot of time to redraw. Each instance of this class is in a common Forms.SplitterPanel. I use a lot of comments out of habit so i left them in here, maybe they'll add some light.
Public Class clsFeedImgBox
Inherits PictureBox
Private iRank As Integer 'rank in whatever feed this file gets put in
Private iRankTarget As Integer 'rank to move to when rank feed event starts
Private iTopStart As Integer 'starting top location before feed event
Private iTopTarget As Integer 'final Top location after feed event
Private WithEvents tMyTimer As New System.Timers.Timer
Private WithEvents oParent As FeedBase 'splitter panel, all location info comes from the parent
Public Sub New(ByRef sender As FeedBase, ByVal rank as Integer)
'set objects
oParent = sender
'set .Image property to pre-made thumbnail
Image.FromFile(ThumbPath) 'ThumbPath is a property which is set by this point (some code has been removed)
'setup initial position
setPanelLocation(rank)
'set autosize
Me.SizeMode = PictureBoxSizeMode.StretchImage
'set Image Scroll timer interval to 20 fps (1000 / 20 = 50)
tMyTimer.Interval = 50
End Sub
Public Sub scroll(ByVal newRank As Integer)
'setPanelLocation(newRank) <== this works, timed movements don't
iRankTarget = newRank
iTopStart = Me.Top
iTopTarget = oParent.ImgTop(newRank) 'gets an integer for the new Top location
tMyTimer.Start()
End Sub
Private Sub myScrollStep() Handles tMyTimer.Elapsed
'tMyTimer.Enabled = False 'this idea with the enabled = True at the end didn't work
iTickCount += 1
Dim iScrollPerc As Integer 'scroll % between Start and End * 100
iScrollPerc = oParent.ScrollStep(iTickCount, Rank) 'this part works
Console.WriteLine(strThumbName & " scrollPerc: " & iScrollPerc.ToString)
If iScrollPerc >= 100 Then
'scroll event complete
Console.WriteLine(strThumbName & " SetFinalLocation")
Me.setPanelLocation(iRankTarget) '<== This line doesn't work here, but works when called by other means
'stop Feed updates
tMyTimer.Stop()
'reset iTickCount for next movement
iTickCount = 0
Else
'scrolling still going
Dim newTop As Integer
newTop = Math.Round(iTopTarget - (((100 - iScrollPerc) * (iTopTarget - iTopStart)) / 100)) 'this part works
'Console.WriteLine(strThumbName & " TopTarget: " & newTop)
Me.Top = newTop 'Nothing happens here
End If
'Me.Left = oParent.ImgLeft
'Me.Width = oParent.ImgWidth
'Me.Height = oParent.ImgHeight 'that didn't work
'Me.Refresh() 'this didn't work
'Invalidate() 'this didn't do much good either
'Me.Update() 'Aaaaand no cigar, time for StackOverflow
'tMyTimer.Enabled = True
End Sub
Public Sub setPanelLocation(ByVal rank As Integer)
iRank = rank
Me.MyRePaint()
End Sub
Public Sub MyRePaint()
'repaint image box with everything in it's current rank
Me.Left = oParent.ImgLeft
Me.Top = oParent.ImgTop(iRank)
Me.Width = oParent.ImgWidth
Me.Height = oParent.ImgHeight
End Sub
End Class
What gives? There must be some inner workings of VB.NET that will help me figure this out. I'm using VS 2012 and Win8
You could make a WPF application and use a Slider control instead of "manually" making a slider with planes, picture boxes, etc, etc.