Since I can't put in parameters, how can I respect the following signature?
Private Sub SetFocusToRow(ByRef ultraGridRow As Infragistics.Win.UltraWinGrid.UltraGridRow)
grdSoldeOuverture.ActiveCell = ultraGridRow.Cells(0)
grdSoldeOuverture.PerformAction(Infragistics.Win.UltraWinGrid.UltraGridAction.EnterEditMode)
End Sub
When I call it like this
Me.BeginInvoke(New MethodInvoker(AddressOf Me.SetFocusToTemplateAddRow))
I'm on .NET 2.0 in Visual Studio 2005 with Microsoft Visual Basic 2005 so a lambda expression is not an option.
You can use a lambda to capture the requirements and pass them in:
Foo arg = GetTheFoo()
BeginInvoke(New MethodInvoker(Sub() SetFoo(arg)))
Edit:
First, change your method to not pass ByRef - this is unnecessary:
Private Sub SetFocusToRow(ByVal ultraGridRow As Infragistics.Win.UltraWinGrid.UltraGridRow)
grdSoldeOuverture.ActiveCell = ultraGridRow.Cells(0)
grdSoldeOuverture.PerformAction(Infragistics.Win.UltraWinGrid.UltraGridAction.EnterEditMode)
End Sub
Next, define a delegate:
' Define your delegate:
Delegate Sub SetFocusToRowDelegate(ByVal ultraGridRow As Infragistics.Win.UltraWinGrid.UltraGridRow)
Then you can call via:
BeginInvoke(new SetFocusToRowDelegate(AddressOf SetFocusToRow), arg)
Since lambdas cause a problem you could try implementing them manually using an object:
Class FooCurry
Private bar as Foo
Private Sub new (foo as Foo)
bar = foo
End Sub
Public sub DoFoo()
bar.SetFoo()
EndSub
End Class
dim foocurry as new FooCurry(foo)
BeginInvoke(New MethodInvoker(AdressOf foocurry.DoFoo))
This is how lambdas are implemented under the hood, so this should work. You could generalise the object to take a delegate and use it in more places.
Related
I was beginning to think that I was getting good at VB.net, but not this one has me stumped.
Code looks something like this
Public Class MyServer
.....
Public myMQTTclient = New MqttClient("www.myserv.com")
.....
Private Sub Ruptela_Server(sender As Object, e As EventArgs) Handles
MyBase.Load
<some code>
StartMQTT()
<some more code>
MQTT_Publish(.....)
End Sub
Public Function StartMQTT()
' Establish a connection
Dim code As Byte
Try
code = myMQTTclient.Connect(MQTT_ClientID)
Catch ex As Exception
<error handling code>
End Try
Return code
End Function
Public Sub MQTT_Publish(ByVal DeviceID As String, ByVal Channel As String, ByVal ChannelType As String, ByVal Value As String, ByVal Unit As String)
Dim myTopic As String = "MyTopic"
Dim myPayload As String = "My Payload"
Dim msgId As UShort = myMQTTclient.Publish(myTopic, Encoding.UTF8.GetBytes(myPayload), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, False)
End Sub
As this stands it works 100% OK. The coding may seem a bit odd, but the intent is as follows :
a) create an object 'myMQTTclient' at module level so it has scope throughout the module
b) run StartMQTT() - It can still see the object.
c) within main program call MQTT_Publish many times - I can still see the object
Now the issue is this... it all goes well until "www.myserv.com" fails DNS, then the underlying winsock code throws an exception.
So ... I'm thinking - no problem - just wrap the declaration in a try block or check that www.myserv.com exists before launching the declaration.
Ah, but you can't put code at module level, it has to be in a sub or function.
Hmmm... now I'm stumped. There has to be a 'proper' way to do this, but I'll be darned if I can figure it out.
Anyone able to help ?
I'd follow the advice from #djv about declaring it just as you need it. To wrap that in a Try... Catch block you can do that in an Init method.
Public Class MyServer
Implements IDisposable ' As per djv recommendation which I second...
Private myMQQTclient As MqttClient
Public Sub Init()
Try
myMQQTClient = New MqttClient("<your url>")
Catch ex As Exception
' Do whatever
End Try
End Sub
' more code and implement the Dispose method...
End Class
You can then go on and implement the IDisposble interface to ensure that you release the resources.
Ok, I am not sure if I have the right library. But I found this Nuget package: OpenNETCF.MQTT which seems to have the class you are using.
I would do it this way
Public Class MyServerClass
Implements IDisposable
Public myMQTTclient As MQTTClient
'Private Sub Ruptela_Server(sender As Object, e As EventArgs) Handles MyBase.Load
' ' <some code>
' StartMQTT()
' ' <some more code>
' ' MQTT_Publish(.....)
'End Sub
Public Sub New(brokerHostName As String)
myMQTTclient = New MQTTClient(brokerHostName)
End Sub
Public Function StartMQTT()
' Establish a connection
Dim code As Byte
Try
code = myMQTTclient.Connect(MQTT_ClientID)
Catch ex As Exception
'<error handling code>
End Try
Return code
End Function
Public Sub MQTT_Publish(ByVal DeviceID As String, ByVal Channel As String, ByVal ChannelType As String, ByVal Value As String, ByVal Unit As String)
Dim myTopic As String = "MyTopic"
Dim myPayload As String = "My Payload"
Dim msgId As UShort = myMQTTclient.Publish(myTopic, Encoding.UTF8.GetBytes(myPayload), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, False)
End Sub
#Region "IDisposable Support"
Private disposedValue As Boolean
Protected Overridable Sub Dispose(disposing As Boolean)
If Not disposedValue Then
If disposing Then
myMQTTclient.Dispose()
End If
End If
disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
End Sub
#End Region
End Class
And now you can see the usage when IDisposable is implemented, in a Using block:
Module Module1
Sub Main()
Using myserver As New MyServerClass("www.myserv.com")
myserver.StartMQTT()
myserver.MQTT_Publish(...)
End Using
End Sub
End Module
This makes it so your object is only in scope in the Using, and the object's Dispose method will automatically be called on End Using
I don't know what the base class was originally and why this was declared Private Sub Ruptela_Server(sender As Object, e As EventArgs) Handles MyBase.Load. It seems like it was possibly a form? You should keep your server code separate from Form code if that was the case. I suppose you could paste the Using into your form load, but then you would be blocking your UI thread. The referenced library has Async support so it might be a good idea to leverage that if coming from a UI.
I've made many assumptions, so I'll stop to let you comment and see how close relevant my answer is.
I am writing a VB form application that redirects the standard output stream of a process and uses it in a UI.
I am having trouble calling methods with parameters that update controls on the form from the OutputHandler sub.
I can call a method without parameters like so
Me.Invoke(New MyDelSub(AddressOf ServerStarted))
Which works fine.
And a bit of googling told me that to call a method with parameters I should do this:
Dim del As JoinDelegate = AddressOf PlayerJoins
del.Invoke(username)
With this delegate and method pair:
Private Delegate Sub JoinDelegate(ByVal username As String)
Private Sub PlayerJoins(ByVal username As String)
PlayersBox.Items.Add(username)
'Do other stuff
End Sub
But this produces an IllegalOperationException the first time the method tries to access a control.
1) Supposing you have a method like this:
Public Sub DoSomething(value1 As String, value2 As String)
MessageBox.Show(String.Format("{0} {1}", value1, value2))
End Sub
You can call it using invoke this way:
Me.Invoke(Sub() DoSomething("Hello", "World!"))
2) If you want to make thread safe call to a control you can write the method this way:
Public Sub AddItemToListBox1(item As String)
If (ListBox1.InvokeRequired) Then
ListBox1.Invoke(Sub() AddItemToListBox1(item))
Else
ListBox1.Items.Add(item)
End If
End Sub
Then it's enough to call it in a the UI thread or in another thread the same way simply:
AddItemToListBox1("some item")
The call would be thread safe.
E.g.
Private Sub SetControlText(control As Control, text As String)
If control.InvokeRequired Then
control.Invoke(New Func(Of Control, String)(AddressOf SetControlText), control, text)
Else
control.Text = text
End If
End Sub
Call that method from any thread.
I would like to organize a class as follows (pseudocode)
Class MyClass
sub New(MethodEnabled as integer)
if MethodEnabled = 0
make MyMethod() to be Sub0()
else
make MyMethod() to be Sub1()
end if
end sub
sub MyMethod()
invoke(either sub0 or sub1 depending on "MethodEnabled" value)
end sub
sub Sub0()
some code here
end sub
sub Sub1()
some code here
end sub
End Class
What I wish is to have the sub "MyMethod()" to invoke (or "to be") either Sub0() or Sub1(), depending on how the class was constructed (either with MethodEnabled=0, or MethodEnabled=1).
I gather intuitively that I can do that by using delegates and invoke, but I am not much clear on how to actually do it, in practice.
Can anybody show me how I can possibly do this in the most elegant way. C# of VB.NET examples would be equally great. Thank you!
You need to either declare a delegate type or use System.Action, and then use an instance of that delegate type:
Class [MyClass]
Private Delegate Sub myDelegate()
Private myDelegateInstance As myDelegate
'or you could just leave out 'myDelegate' and use 'System.Action'
Sub New(ByVal MethodEnabled As Integer)
If MethodEnabled = 0 Then
myDelegateInstance = AddressOf Sub0
Else
myDelegateInstance = AddressOf Sub1
End If
End Sub
Sub MyMethod()
myDelegateInstance()
End Sub
Sub Sub0()
'some code here
End Sub
Sub Sub1()
'some code here
End Sub
End Class
I'm continuing to try to learn VB.net, and I visit here often.
So, I'm back again, with a slightly different question. I received great help previously, and hope to avail myself again.
I have this CSharp code:
public delegate void MyHandler(string DataLine);
foo.Handler = new MyHandler(MySub);
void MySub(string DataLine);
(When I hover over "MyHandler", the VS helper says "MyHandler.MyHandler(void (string) target)"
I want to set up the delegate in VB.net, but I can't seem to relate the three items so they all work together:
Private Delegate Sub MyHandler(ByRef DataLine as string)
?????? as MyHandler
Private Sub MySub (ByRef DataLine as string)
Does the "??????" need to be a Dim {something}, or a Declare {something} or ??? Or is there an error in one of the other two lines?
(Let me know if there is any missing info)
Thanks
Charlie
In VB.Net, you can use AddressOf to assign a Sub to a Delegate:
foo.Handler = AddressOf MySub
Given this:
Private Delegate Sub MyHandler(ByRef DataLine as string)
Private Sub MySub(ByRef DataLine as string)
' Do something here
End Sub
You can declare and instantiate the delegate, like this:
Dim TheHandler As MyHandler
TheHandler = AddressOf MySub
I have a class in VB.NET that has a method (called CurrentValue) that returns a number. There is also an event that the class raises to indicate the number has changed. In the event handler on my form, I update a textbox using the exposed method.
Sort of like this:
Public WithEvents MyClass as New CustomClass
Private Sub MyClass_DataChanged() Handles MyClass.DataChanged
Text1.Text = MyClass.CurrentValue
End Sub
When I run this I get a "Debugger.Runtime.CrossThreadMessagingException" error. What could be doing this? I am instantiating MyClass in the same form that contains the textbox.
I can also set properties of the MyClass object without any trouble.
OK, here's what I did:
In the form I have this to handle the event:
Public Delegate Sub MyClassDataChangedDelegate()
Sub MyClassDataChanged() Handles MyClass.DataChanged
If Me.InvokeRequired Then
Me.Invoke(New MyClassDataChangedDelegate(AddressOf MyClassDataChanged))
Else
Me.Text1.Text = MyClass.CurrentValue
End If
End Sub
This seems to work. Thanks for the suggestion.