Can any one translate the following syntax to vb.net.
m_TextBox.Loaded += TextBoxLoaded
m_TextBox.Loaded -= TextBoxLoaded;
private void TextBoxLoaded(object sender, RoutedEventArgs e)
{
Init();
}
..
containsTextProp.AddValueChanged(m_TextBox, (sender, args) => UpdateAdorner());
...
private void UpdateAdorner()
{...}
Despite the 25% acceptance rate, here it is:
AddHandler m_TextBox.Loaded, AddressOf TextBoxLoaded
RemoveHandler m_TextBox.Loaded, AddressOf TextBoxLoaded
Private Sub TextBoxLoaded(ByVal sender as Object, ByVal e as RoutedEventArgs)
Init()
End Sub
Your call to AddValueChanged can't be directly translated, as VB.NET's lambda expression support is not as robust as C#'s. In particular, VB.NET lambdas must be an expression, so you must either return a value or call a Function. In your case, you would be calling a Sub, which isn't allowed in VB.NET. You should consider changing the signature of UpdateAdorner to be a standard event handler (like the TextBoxLoaded method) and pass AddressOf UpdateAdoerner to AddValueChanged.
Like this:
containsTextProp.AddValueChanged(m_TextBox, AddressOf UpdateAdorner);
...
Private Sub UpdateAdorner(ByVal sender as Object, ByVal e as EventArgs)
...
End Sub
There are plenty of online converters, you shuold probably try that first next time and post here if it doesn't work or you have a problem.
AddHandler m_TextBox.Loaded, AddressOf TextBoxLoaded ' per #Adam Robinson'
RemoveHandler m_TextBox.Loaded, AddressOf TextBoxLoaded ' per #Adam Robinson'
Private Sub TextBoxLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
Init()
End Sub
Private Sub UpdateAdorner()
End Sub
You might find the "C# and VB.NET Comparison Cheat Sheet" useful.
http://aspalliance.com/625
You can toss it in an app, build it, then open the app in .NET reflector. .NET Reflector can take the IL and "turn it into" C#/VB.NET, etc.
Related
I had difficulty deleting an event
, I only call contextmenu temporarily (assigning the event and after the event has finished I no longer use it), and so on for each call.
sub register()
Dim f_Cm As Windows.Forms.ContextMenuStrip = New System.Windows.Forms.ContextMenuStrip(Me.components)
AddHandler f_Cm.Closed, Sub() f_Cm_Closed(f_Cm)
end sub
'mycode1
Private Sub f_Cm_Closed(f_Cm As Windows.Forms.ContextMenuStrip)
'....mycode
RemoveHandler f_Cm.Closed, Sub() f_Cm_Closed(f_Cm)
End Sub
'mycode2
Private Sub f_Cm_Closed(f_Cm As Windows.Forms.ContextMenuStrip)
'....mycode
Dim e1 As ToolStripDropDownClosedEventArgs = address of f_Cm_Closed(f_Cm)
RemoveHandler f_Cm.Closed, e1
End Sub
Do I need to delete them in this case? and how to do this?
Thanks you!
Sub() f_Cm_Closed(f_Cm) is what's called a lambda expression. Lambda expression are basically methods without a name; they're useful shortcuts in some situations. What you are doing in the code Sub() f_Cm_Closed(f_Cm) is creating a new, nameless method, which then calls f_Cm_Closed(f_Cm).
This isn't what you want, you want to pass a reference directly to your handler so you can remove it later. For that, you use AddressOf.
Before you can do that, the method signatures will have to match. So
Private Sub f_Cm_Closed(f_Cm As Windows.Forms.ContextMenuStrip)
will have to become
Private Sub f_Cm_Closed(sender As Object, e As ToolStripDropDownClosedEventArgs)
sender will always be f_Cm, so you can cast like so:
Dim f_Cm As Windows.Forms.ContextMenuStrip = sender
To pull everything together, your AddHandler call now becomes:
AddHandler f_Cm.Closed, AddressOf f_Cm_Closed
And your method f_Cm_Closed becomes:
Private Sub f_Cm_Closed(sender As Object, e As ToolStripDropDownClosedEventArgs)
Dim f_Cm As Windows.Forms.ContextMenuStrip = sender
RemoveHandler f_Cm.Closed, AddressOf f_Cm_Closed
End Sub
As a final thought, I have no idea why you would want to remove the handler for the Closed event after the menu is closed. But this is how you would restructure your code to do it.
I am new to VB.NET and I'm stuck with the following:
I want to perform some operations before a programmatically-created Form closes.
I need to handle the Close event of my Form (created in code).
How can I do this?
Below is how they do it with C#
{
Form1 f = new Form1();
f.FormClosed += new FormClosedEventHandler(f_FormClosed);
f.Show();
}
void f_FormClosed(object sender, FormClosedEventArgs e)
{
// Do stuff here
}
In VB.NET events are handled a little bit differently.
If you want to use the Handles clause in addition to the form's FormClosed delegate declaration, you need to declare the object (Form in your case) with the WithEvents key word at a module level:
Private WithEvents frmX AS New Form
Then you can just write:
Private Sub frmX_FormClosed(sender As Object, e As FormClosedEventArgs) Handles frmX.FormClosed
End Sub
The compiler will then take care of attaching and detaching the handler as appropriate.
If you want to take control yourself, then declare the Form wherever you'd like and use the AddHandler and RemoveHandler directives as appropriate:
// Define the handler delegate as usual:
Private Sub frmX_FormClosed(sender As Object, e As FormClosedEventArgs)
End Sub
// Somewhere else in your code use this:
// To attach the handler:
AddHandler frmX.FormClosed, AddressOf Form5_FormClosed
// To detach the handler:
RemoveHandler frmX.FormClosed, AddressOf frmX_FormClosed
The .FormClosed will popup in the AddHandler / RemoveHandler context.
Note the AddressOf keyword. It is mandatory when you need to specify a delegate.
"but FormClosed in C# Form isn't available in vb.NET" - Infact it is, but events aren't generally shown by the IntelliSense if you aren't currently in a statement requiring an event.
In VB.NET you use the AddHandler statement to subscribe to events.
Dim f As New Form1
AddHandler f.FormClosed, AddressOf f_FormClosed
f.Show()
...
Private Sub f_FormClosed(sender As Object, e As System.FormClosedEventArgs)
End Sub
I'm seeing some strange behavior where the RunWorkerCompleted event for one of two threads I start isn't being called depending on how I call them. Check out the code below, and the two methods of firing the threads, good() and bad().
Public Class Form1
Private WithEvents bw As System.ComponentModel.BackgroundWorker
Private WithEvents bw2 As System.ComponentModel.BackgroundWorker
Private starts As Integer = 0
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bw.DoWork
starts += 1
Threading.Thread.Sleep(e.Argument)
End Sub
Private Sub bw_Completed(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
MessageBox.Show("Ending " + starts.ToString())
End Sub
Private Sub bad()
bw = New System.ComponentModel.BackgroundWorker()
bw.RunWorkerAsync(5000)
Threading.Thread.Sleep(500)
bw = New System.ComponentModel.BackgroundWorker()
bw.RunWorkerAsync(5)
End Sub
Private Sub good()
bw2 = New System.ComponentModel.BackgroundWorker()
AddHandler bw2.DoWork, AddressOf bw_DoWork
AddHandler bw2.RunWorkerCompleted, AddressOf bw_Completed
bw2.RunWorkerAsync(500)
bw2 = New System.ComponentModel.BackgroundWorker()
AddHandler bw2.DoWork, AddressOf bw_DoWork
AddHandler bw2.RunWorkerCompleted, AddressOf bw_Completed
bw2.RunWorkerAsync(5)
End Sub
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
'good()
bad()
End Sub
End Class
In both cases the DoWork event is called for both threads. But in the bad() case, only the second thread fires the RunWorkerCompleted event. This is obviously due to the two different ways I'm using VB to handle events here. I'm looking for an explanation of this behavior, preferably with a link to some documentation that could help me understand how these events are being handled in VB better. It seems strange to me that just reusing a variable name here seems to either dispose of the thread before it's done or else just make it stop firing events.
Where is this automatic unsubscribing documented?
In the Visual Basic Language Specification, a document you can download from Microsoft. Chapter 9.6.2 "WithEvents Variables" says this:
The implicit property created by a WithEvents declaration takes care of hooking and unhooking the relevant event handlers. When a value is assigned to the variable, the property first calls the remove method for the event on the instance currently in the variable (unhooking the existing event handler, if any). Next the assignment is made, and the property calls the add method for the event on the new instance in the variable (hooking up the new event handler).
The bolded phrase describes the behavior you see. It is rather important it works that way. If it didn't then you could never unsubscribe from an event and the event subscriptions would pile on without limit.
it seems that adding for example a button Dim myButton as New Button and then addHandler to mySub("lol", 255) is not possible.
Where mySub is Shared Sub MySub(byRef myString as string, myInteger as Integer)
So: addHandler myButton.click, addressOf mySub("lol", 255) - returns an error saying it does not work with parentheses or whatever.
I somehow see why this might not be possible, so I'm looking for a work-around on this problem.
Please help _jakeCake
First of all the syntax for AddHandler would be:
AddHandler myButton.click, AddressOf mySub
Secondly the signature of the eventhandler procedure must match the signature of the event like so:
Private Sub myButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
[...]
End Sub
Maybe you could look into using a lambda expression when you add the event. When using lambda's in VB.NET the function must return a value and does not support multi-line statements.
Dim myButton As New Button
AddHandler myButton.Click, Function(senderObj, args) myFunc("lol", 255)
Is RaiseEvent thread safe?
In C# you write
if (event != null)
{
event.invoke();
}
and the C# code is not thread safe....
If I need to do thread safe events, I write this:
Class Test
Public Event Click(ByVal sender As Object, ByVal e As EventArgs)
Public Event MouseIn(ByVal sender As Object, ByVal e As EventArgs)
Private Delegate Sub EventArgsDelegate(ByVal e As EventArgs)
Private ReadOnly _parent As Control
Public Sub New(ByVal parent As Control)
_parent = parent
End Sub
Private Sub OnClick(ByVal e As EventArgs)
If _parent.InvokeRequired Then
_parent.Invoke(New EventArgsDelegate(AddressOf OnClick), e)
Else
RaiseEvent Click(Me, e)
End If
End Sub
Private Sub OnMouseIn(ByVal e As EventArgs)
If _parent.InvokeRequired Then
_parent.Invoke(New EventArgsDelegate(AddressOf OnMouseIn), e)
Else
RaiseEvent MouseIn(Me, e)
End If
End Sub
End Class
Then whenever I need to raise the event I just use the OnClick(new eventargs(...)), etc. If you use Reflector you can observe that most thread safe controls use a similar system.
In C# you rather write:
EventHandler h= myEvent;
if (h!=null)
h(...);
This avoids the obvious problem (i.e. the unsubscribing between the test and the call), but this isn't thread-safe either.
Calling an event implies the listener is ready to process this event. This heavily depends on your specific situation, and is usually achieved through the use of synchronization mechanisms.
What exactly do you mean by "Thread safe" ?