My project is built in VB.Net
Many times I find that Visual Studio has added subroutines to my code files even if a subroutine of the exact same name already exists. This can cause debugging nightmares as the new empty routine seems to override the correct routine. I think this can happen if I double-click on a control in the form Design view, but I try not to do this.
Is there any way to turn this off?
Example:
Hand entered
Private Sub TS_Main_View_Network_Click Handles TS_Main_View_Network.Click
System added:
Private Sub TS_Main_View_Network_Click( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TS_Main_View_Network.Click
I guess that the system adds the second routine because the argument list (which is unneeded but may be required) list is missing from the first routine.
In the example you gave in the comments the methods are overloaded.
I assume you added the first one by hand because the signature is not correct for an event handler. .NET event handlers should have a signature that matches void EventHandler(object sender, EventArgs e).
Private Sub TS_Main_View_Network_Click Handles TS_Main_View_Network.Click
Private Sub TS_Main_View_Network_Click( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TS_Main_View_Network.Click
When Visual Studio adds an event handler on double click (which you can't disable out-of-the-box) it always creates a method with the correct signature.
Actually, your code takes advantage of some VB features (late-binding, perhaps) to let your declare an event handler without arguments. You cannot do that in a purely static-typed language, like C#, because it is not valid IL: the method without arguments cannot be assigned to an EventHandler delegate (the type of the Click event). Behind the scenes the VB compiler creates some sort of adapter for the method with no arguments.
This happens when you write a handler for a control that does not exist, then add the control to the form in design mode, and then double click on that control.
Related
I am trying to use the circular progress bar solution that was provided at
Visual basic circular progress bar
However I am getting a lot of error messages when I try to incorporate it within a Windows Form that has textbox entries (have to do with System.EventArgs versus PaintEventArgs and MyBase.Load versus Me.Paint).
I tried "mixing" both handles like this:
Private Sub LoginForm1_Load(ByVal sender As System.Object, e As System.EventArgs, g as PaintEventArgs) Handles MyBase.Load, Me.Paint
but of course that bombed out. Can someone please advise what are my alternatives here?
Thanks
You're taking something very easy and making it hard. ALL drawing gets done in the Paint event handler or a method called from the Paint event handler. That's it, that's all when it comes to drawing. You already know how to do that because you already have the code to do it from another question. Use that code.
If the code that does the drawing needs to get data from elsewhere to know what to draw then do that. There's nothing magical about a method using the value of one or more fields to do its work. The data in that field(s) can be put there by any other method, e.g. the Load event handler of the form, the TextChanged event handler of a TextBox or the Click event handler of Button.
Here's a simple example that will draw whatever is in a TextBox as the user types:
Private textToDraw As String
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.Text
textToDraw = TextBox1.Text
'Force a Paint event to be raised.
Invalidate()
End Sub
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
e.Graphics.DrawString(textToDraw, Font, Brushes.Black, PointF.Empty)
End Sub
Put the data where it can be accessed, raise a Paint event, do the drawing. Simple!
The main point to note there is that calling Invalidate with no arguments will cause the entire control it's called on (the form, in this case) to be repainted and that should be avoided if possible. You should calculate and specify the smallest area possible that has or could have changed and pass that when calling Invalidate. That way, parts of the control that definitely haven't changed will not be repainted, speeding up the process. You draw everything every time but the actual repainting of pixels on the screen is the slow part of the operation and so should be minimised. You might read this for more information.
When trying to use the ItemCheck event of a ListView, I have found that the event fires before the item is checked, so running code that looks to see which items are checked doesn't work as expected, because the item that's just been checked still has its old Checked value.
Private Sub MyListView_ItemCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckEventArgs) Handles MyListView.ItemCheck
There's an ItemChecked event in .NET Framework, but alas, this is missing in .NET Compact Framework. Is there some other way of executing code after a ListViewItem has been checked?
You can use this event, as the arguments expose the items which was checked and its value through the ItemCheckEventArgs.NewValue and ItemCheckEventArgs.Index properties.
You should be able to use this information, with the other items in your listview to determine the current state of the object.
After trying a few things and looking around the hidden events like MouseUp which don't seem to fire, I came up with this solution:
Private Sub MyListView_ItemCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckEventArgs) Handles MyListView.ItemCheck
Me.MyListView.Items(e.Index).Checked = CType(e.NewValue, Boolean)
Call DoStuffWithCheckedItems()
End Sub
It seems to work quite reliably. I'm basically just updating the Checked property myself.
I'm building a "plug-in" of sorts for an already-deployed VB6 executable. I'm using .NET along with COM-Interop. The VB6 creates a blank form and then loads my .NET UserControl into it (however by now the .dll has been compiled into a .ocx ActiveX UserControl that can be seen by VB6).
I've got it working well, but I would like to be able to close the VB6 parent form from inside of my .NET code. I am able to add VB6 code into my VB6-ifyed UserControl, but I cannot seem to find an event that fires when the UserControl is destroyed.
What I've tried so far:
Calling ParentForm.Close from the Disposing event of my .NET control. Receive error Object Reference not set to Instance of an Object.
Trying to close from the VB6 (I am able to get a handle on the parent form from there). Using ControlRemoved, Terminated, and a couple other hackish workarounds that truly make no sense in retrospect don't get triggered.
Calling Application.Exit (truly getting desperate at this point) closes the whole Application (who woulda thunk...)
I looked in the VB6 Interop code that I put in my .NET control and the following does look promising:
#Region "VB6 Events"
'This section shows some examples of exposing a UserControl's events to VB6. Typically, you just
'1) Declare the event as you want it to be shown in VB6
'2) Raise the event in the appropriate UserControl event.
Public Shadows Event Click() 'Event must be marked as Shadows since .NET UserControls have the same name.
Public Event DblClick()
Private Sub InteropUserControl_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Click
RaiseEvent Click()
End Sub
Private Sub InteropUserControl_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.DoubleClick
RaiseEvent DblClick()
End Sub
#End Region
Is it just a matter of adding an event in this section? I'm not terribly familiar with Interop, or VB6 for that matter.
Alright, I figured it out and will post what I did for future generations :P
I was right with the event handlers in the VB6 code, and MarkJ was correct as well.
I created an event in the .NET code,
Public Event KillApp()
and then when I wanted to close everything, raised it:
RaiseEvent KillApp()
In the VB6 UserControl code, I declared the event again,
Public Event KillApp()
and then added a handler for it:
Private Sub MenuCtl_KillApp()
Unload Me.ParentForm
End Sub
where MenuCtl is my instance of the .NET control, and Me.ParentForm is the VB6 container form that houses the control. It now correctly closes the form!
In retrospect it makes a lot of sense, but I was unaware that you could pass events back and forth between managed/unmanaged that easily.
My “form1” is just a simple page with buttons that launch different forms which do all the work, the "form1" code for the first four buttons is below.
What I want is for each form to run in a separate thread.
Public Class Main
Private Sub btnDownLoadStockPrices_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDownLoadStockPrices.Click
LoadStocksFromDownloadSite.Visible = True
End Sub
Private Sub btnLoadOptionsIntoDatabase_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadOptionsIntoDatabase.Click
LoadOptionsIntoDatabase.Visible = True
End Sub
Private Sub btnVerifyDatabases_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnVerifyDatabases.Click
VerifyDatabase.Visible = True
End Sub
Private Sub btnAnalyzeStock_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAnalyzeStock.Click
AnalyzeSingleStock.visible = True
End Sub
End Class
I’ve found plenty of code examples to have different buttons on a single form run a subroutine in a separate thread, but for some reason I can’t seem to apply it to an entire form.
I think it’s something simple, like I need to tie each new thread as a handle to each forms “load” routine, but I just can’t get it to work. I don’t care about “synchronizing” threads at all, as each form is really a completely different functional program.
Any help would be much appriciated!
This isn't very common; generally it's best to limit all UI stuff to a single thread. But if you're convinced that you need each form to run on a separate thread, you must take into account the Windows API event handling model. The [over]-simplified version is that each form must have its own message loop to remove event messages from the queue and process them, so if you want to open a form on a new thread, you need to create that message pump.
The easiest way to do that is using the Application.Run method, and let the .NET Framework handle creating that message pump for you. For example:
Dim frm As Form1 = New Form1()
Application.Run(frm)
From looking at the code shown in your question, I can't discern any possible reason why those forms would need to run on separate threads. You can call the Show method of multiple forms so that they will be displayed on the screen at the same time. They won't block each other as long as you don't use the ShowDialog method, which displays each as a modal dialog. This is the way so many applications display multiple toolbox windows and other kinds of forms on the screen at the same time.
If you need to do some type of processor-intensive calculation, you still don't need to run each on a separate thread. Spin up a background thread (the BackgroundWorker class makes this very simple) and update the appropriate form's UI using the Invoke method.
You can certainly do this on Win32 but I don't know how well this maps over to .net.
The essential issue is that window handles have thread affinity. So you really need all interaction with them to happen in that thread. Essentially this means that you create all the window handles associated with that form in its thread. You also need to run a message loop in the thread.
The reason that people usually run all the UI out of the main thread and handle long-running actions in separate threads is that it is easier that way. You should ask yourself again why you want to do it this non-standard way.
I suspect you are not quite seeing the full picture. The need for threads in a desktop app principally arises when you have long running actions. Usually you want to keep your UI responsive and providing feedback for the long running action. Doing so leads to threads.
However, in your proposed solution you now have a multitude of extra threads and complexity, and you are still faced with the original problem! A long running action on one of your forms will hang it unless you perform that action in a separate thread, and once again we reach the standard solution to the problem.
I have an app with 24 different Forms. They have some security options based on which the 5 different buttons Submit, Approve, 2nd Approve, 3rd Approve, Reject etc get enabled disabled.
Now I designed a MainForm that has all the buttons and the security code for them. I have created eachform as a usercontrol and load them dynamically based on which form the user wants. My loading works perfectly fine. I load the control and Add it to the place holder in the Page load event of the main page.
Now when the user selects the Submit button I want to call the Save method inside the usercontrol of the Form as each form will have a separate Save. So when I try this code snippet I get the Null reference error. Do let me know how to resolve it.
Private UCDynamic As UserControl
Then on Page Load event I use this code
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If not Me.IsPostBack
UCDynamic = LoadControl("Controls/BkCode.ascx")
Me.PlaceHolderForm.Controls.Add(UCDynamic)
End if
Then on the ButtonClick Event for Submit I do this
Protected Sub Save_OnClick(ByVal sender As Object, ByVal e As EventArgs)
Save()
End Sub
Sub Save()
CType(Me.UCDynamic, controls_BkCode).Save()
End Sub
Thats where I get the cast Null reference error. So is it that after post back the control no longer exist on the page. Any ideas will be greatly appreciated.
Thanks.
Http protocol is stateless, so all server variables are nothing after postback.
Have you tried to find it with FindControl, it should be stored in the Viewstate of your Placeholder?
Directcast(Me.PlaceHolderForm.FindControl("the_id_of_your_usercontrol"),
controls_BkCode).Save()
Hi Tim Thanks for your help. But Findcontrol does not work for the placeholder. Though I have the viewstate enabled for the placeholder yet it does not hold the control after post backs.
Finally resolved this issue by moving my LoadControl code out of If not is postback. So I load the control every time and the code inside the control takes care of the logic of post backs and the viewsataes for the control.