I'm having a strange hang issue with my VB.Net application. When the user clicks an update button, the below is run as a thread to do some long calculations on the data. It disables the control, shows a 'Working...' text box, does the work, re-enables the controls and gets rid of the 'Working...' text box. Occasionaly (I've never reproduced while debugging), the users window freezes and hangs. When it happens CPU usage is 0 so its done with the calculations, but the controls still show as disabled and the 'Working...' text box is still visible, although the window is completely stuck and will not update. This will stay this way indefinitely (users have tried waiting up to 30 minutes). Oddly, I can 'unstick' the window only by clicking the minimize/restore buttons from the right click menu of the window on the task bar. After a short delay the window springs back to life. The minimize/restore of the window itself don't seem to have an effect.
So my question, what am I doing wrong in my below thread?
Dim Thread As New Threading.Thread(AddressOf SubDoPriceUpdateThread)
Thread.Start()
Thread:
Private Sub SubDoPriceUpdateThread()
Dim Loading As New TextBox
Try
CntQuotePriceSummary1.Invoke(New Action(Of Control)(AddressOf CntQuotePriceSummary1.Controls.Add), Loading)
CntQuotePriceSummary1.Invoke(New Action(Sub() CntQuotePriceSummary1.Enabled = False))
Loading.Invoke(New Action(AddressOf Loading.BringToFront))
Loading.Invoke(New Action(Sub() Loading.Text = "Working..."))
'***Long running calculations***
Invoke(New Action(AddressOf FillForm))
Finally
CntQuotePriceSummary1.Invoke(New Action(Of Control)(AddressOf CntQuotePriceSummary1.Controls.Remove), Loading)
CntQuotePriceSummary1.Invoke(New Action(Sub() CntQuotePriceSummary1.Enabled = True))
Loading.Invoke(New Action(AddressOf Loading.Dispose))
End Try
End Sub
Per Hans's comments, its clear that the Loading text box is not created on the UI thread and that's what would've cause the deadlock issue. I've rewritten the code.
Private Sub SubDoPriceUpdateThread()
Dim Loading As TextBox
Invoke(Sub() Loading = New TextBox)
Try
Invoke(Sub()
CntQuotePriceSummary1.Controls.Add(Loading)
CntQuotePriceSummary1.Enabled = False
Loading.BringToFront()
Loading.Text = "Working..."
End Sub)
'***Long running calculations***
Invoke(Sub() FillForm())
Finally
Invoke(Sub()
CntQuotePriceSummary1.Controls.Remove(Loading)
CntQuotePriceSummary1.Enabled = True
Loading.Hide()
Loading.Dispose()
End Sub)
End Try
End Sub
Related
I am fixing up an old VB6 app that has a significant amount of work in the Form_Load event. As a result, it takes several seconds for the app to actually appear after the user double-clicks it.
I tried setting Screen.MousePointer = vbHourGlass at the top of Form_Load, but it has no effect.
I've also tried adding DoEvents and Me.Refresh, also to no avail. As a result of this, the user has no indication that anything is going on during this time.
What can I do to show the hourglass when the user double-clicks on the app?
Before call form, set screen.mousepointer=11
screen.mousepointer=11
myform.show
screen.mousepointer=0
You need to allow the form to load, you can't do any GUI stuff until that's happened. Use a timer to run your initilising code and show the mouse as an hourglass while this is going on, or a splash screen with a progress bar.
http://www.vb6.us/tutorials/multiple-form-splash-screen-tutorial
I'm facing a weird case in VB6, which is, when I show a form in respect with another OwnerForm, if I did this two/three times for example, when I close all the child forms, suddenly the OwnerForm disappear on background (lose focus and the previous application will be on top), and I will have to click on it on the task bar to show the form again!
A quick sample will be something like that:
Private Sub Command1_Click()
Command1.Enabled = False
Dim frm As New Form1
frm.Show 0, Form1
End Sub
Is there any solution for this?
Thanks.
You're showing the child form on top non-modally, ie, you can have any number of child forms of that type open. When you close them, sometimes the form / app that spawned them will lose focus and disappear behind other applications - as you are experiencing.
You might be able to hide the form being closed (use the _QueryUnload event and cancel the unload), hide, then set the ZOrder on the parent form (to bring it to the front), then carry on unloading the form that is being closed.
Let me know how you get on.
I have a custom control that's essentially a drawing canvas, and a program that uses it for editing files. When a new file is opened, though, something very strange can happen.
If the user double-clicks on the file in the Open File dialog (standard TOpenDialog control) instead of selecting an item and hitting ENTER, the canvas underneath registers a click event and ends up executing a draw action at the position of the cursor immediately after loading is complete.
Obviously this is not the intended behavior for this. I've noticed before that when you double-click the mouse, the double-click message arrives before the second click message. I think the dialog box might be closing from the double-click, and then the second click message arrives and gets sent to whatever's at the appropriate coordinates now that it's gone.
Is there any way I can make this stop happening? I can't tell my code "after loading, just eat the next click," because it could have been opened with the 'ENTER' key instead, and then it would miss the first legitimate click. Can anyone think of a better way to handle this? (Using Windows 7, in case it makes a difference.)
If there's a "second click message," there's something wrong. (For one thing, Windows doesn't have "click" messages, just mouse-up and mouse-down messages.) A double click goes like this: mouse down, mouse up, double click, mouse up. The dialog disappears between the double-click message and the second mouse-up message. If your control receives the mouse-up message and treats it as a full click, then that explains the issue and you need to stop; a click is always a pair of mouse-down and mouse-up messages. If you haven't gotten both, then it's not a click.
In fact, it is The 2nd mouse-up event got fired on the picture box, which leads to the event handler invocation. This seems an OpenFileDialog bug. Need to add check for the IsMouseCaptured for the mouse up event, one click is mouse down and mouse up, instead of only a mouse up.
I solved it that way (it is of course an work-around):
CFileDialog my_file_dialog(...);
if ( my_file_dialog.DoModal()!=IDOK )
return;
CString fileName= my_file_dialog.GetPathName();
//...
CSelectItemsDlg dlg;
// Avoid that the double-click on the CFileDialog sends the WM_LBUTTONUP message to the next window causing the Unselect of an item that is under the mouse cursor.
// http://www.experts-exchange.com/Programming/System/Windows__Programming/Q_10287063.html#a2476475
MSG msg;
while(PeekMessage(&msg,0,WM_LBUTTONUP,WM_LBUTTONUP,PM_REMOVE));
int DoModalRes = dlg.DoModal();
And you can believe that I have put a big smile on the face of my boss :)
Private IsMouseDown As Boolean
Private Sub picNenIn_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles picNenIn.MouseDown
IsMouseDown = True
'Code
End Sub
Private Sub picNenIn_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles picNenIn.MouseMove
If IsMouseDown Then
'Code
End If
End Sub
Private Sub picNenIn_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles picNenIn.MouseUp
IsMouseDown = False
'Code
End Sub
I have made an application which runs three backgroundworkers simultaneously. It basically updates three datagridviews, which it is doing spot on. My problem is if I press maximizebox button or anywhere in any of the datagridview the program hangs for quite a long time. I am able to use the horizontal scroll but not vertical scrolls. I have tried Backgroundworker_runworkercompleted and it fires as required after threads have updated their respective datagridviews. Is it a normal behaviour or am i doing something wrong any suggestions would be helpful.
P.S: I have run the whole program using step method and their is no infinite loop in the code.
Thanks in advance
Jhon
Place this line of code just before when you are calling Backgroundworker1.RunWorkerAsync() to temporarily disable your datagridview scroll bars.
DataGridView1.ScrollBars = ScrollBars.None
Now Re-enable scroll bars of your datagridview by adding this line of code in BackgroundWorker1_RunWorkerCompleted event.
DataGridView1.ScrollBars = ScrollBars.Both
This will never make your application unresponding.
It sounds like you are still blocking the UI thread somehow. It may be helpful for you to post some code snippets. Also, what is the CPU utilization of your process? If the cpu usage is high, you may be starving the UI thread somehow.
Okay I have found the solution to my problem, while working out sequential elimination of the perceived trouble spots, I called my datagridview outside of the backgroundworker.dowork event and voila that solved the problem.
Moral of the story "NEVER UPDATE A DATA GRID VIEW FROM WITHIN THE BACKGROUNDWORKER THREAD" specially when you don't know what are you doing wrong :). I hope it will help someone in future.
You have to make sure that you are updating the datagridviews from the UI thread.
I had the same problem. When my dataGridViews were being updated from the UI thread, they worked fine. When I tried to add a series of rows to them from the backgroundWorker, they became unresponsive.
To correct this, I added the rows to a dataTable instead. When I kick off the backgroundWorker, I set the .datasource property of the dataGridView to nothing. When the worker completes, I set it back to the dataTable again. This both forces the dataGridView to update itself, and severs the synchronous connection between what it happening in the worker thread, and what is being displayed in the UI, which seems to alleviate the unresponsiveness when the worker completes.
Sample usage:
Private Sub button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn1.Click
If bgWorker1.IsBusy <> True Then
dataGridView1.DataSource = Nothing
bgWorker1.RunWorkerAsync()
End If
End Sub
Private Sub bgWorker_DoWork(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bgWorker1.DoWork
dataTable1.Rows.Add("data")
End Sub
Private Sub bgWorker_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As RunWorkerCompletedEventArgs) Handles bgWorker1.RunWorkerCompleted
dataGridView1.DataSource = dataTable1
dataGridView1.Refresh()
End Sub
It's too late to answer to #Jhon but it seems like it might help other people.
In my case, I was using a BindingSource and the UI only froze if there where so many records that scrollbars had to appear.
When you use a background worker, task or thread to do the work, you have to update your UI controls on the main UI thread.
To do that you can Invoke a method in the corresponding thread.
A simple example:
myDataGridView.Invoke((MethodInvoker)delegate { myBindingSource.DataSource = myData; });
But i prefer this solution:
InvokeIfRequired
We have a VB6 application that uses a non-visible window (form) for DDE communication.
We have some clients reporting that occasionally they can see this window on their desktop.
I did a scan through the code for any visible = true or show's on the form in question, but nothing.
This about all we do with it:
Load frmDDELink
frmDDELink.stuff = stuff
We don't actually explicitly display (or explicitly not display it either).
What could cause a hidden window to be displayed on a user's desktop such that it is visible?
Try and set the location of the form to off-screen.
frmDDELink.ClientLeft = -100
frmDDELink.ClientTop = -100
A misbehaving app on the client's machine could do that. FindWindow() is a notoriously inaccurate API function. On top of that, all VB6 windows have the same class name. Thunder something, iirc. It might be finding your window instead of the one intended, making the wrong window visible.
I like Black Frog's simple hint to set the location off-screen, and nobugz's possible explanation. I would also suggest handling the Form_Activate event and setting the form invisible again.
Private Sub Form_Activate()
'Log something for debugging purposes?'
Me.Visible = False
End Sub
try to set the border into none, or me.visible = false, and set the property not to display in the task bar.