Difference between lambda syntax and addressof VB.NET - vb.net

I've recently entered the joyful world of VB.NET, for the life of me however, I can't seem to figure out why the following is not working.
When I write this code here, all is well:
MyNavigationCommand = New RelayCommand(AddressOf Navigate)
Private Sub Navigate()
Navigator.NavigateTo(NavigationRoutes.DetailScreen)
End Sub
However, when I try to do exactly the same using the lambda syntax, my code inside the lambda doesn't get hit when I click the button that triggers the command.
The following line, doesn't work:
MyNavigationCommand = New RelayCommand(Sub() Navigator.NavigateTo(NavigationRoutes.DetailScreen))
This should work exactly the same as my previous approach, shouldn't it? Or am I missing something?

I'm not sure what's going wrong for you. This is my code that I wrote to test this:
Sub Main
Dim MyNavigationCommand = New RelayCommand(AddressOf Navigate)
Dim MyNavigationCommand2 = New RelayCommand(Sub() Console.WriteLine("!"))
Navigate
MyNavigationCommand
MyNavigationCommand2
End Sub
Public Delegate Sub RelayCommand
Public Sub Navigate()
Console.WriteLine("!")
End Sub
When run this code produces three lines of !.

Related

Creating a new IUI Automation Handler object in order to subscribe to an automation event

So, here it goes. To start, A disclaimer, I understand that MS Access is not built for this kind of work. It is my only option at this time.
I have done just a bit of Automation using UIAutomationClient and I have successfully used its other features, however I cannot for the life of me get it to subscribe to events.
Normally, it is supposed to be a bit like this:
Dim CUI as new CUIAutomation
Dim FocusHandler as IUIAutomationFocusChangedEventHandler
Set FocusHandler = new IUIAutomationFocusChangedEventHandler(onFocusChanged)
C.AddFocusChangedEventHandler(Element,TreeScope_Children, null, FocusHandler)
end function
'
'
Function onFocusChanged(src as Object, args as AutomationEventArgs)
''my code here
end function
Yet when I attempt this, I get the error "expected end of statement" on the line:
FocusHandler = new IUIAutomationFocusChangedEventHandler(onFocusChanged)
additionally, if I leave off the (onFocusChanged) I get the error "Invalid use of new Keyword".
It seems like I am missing a reference somewhere. The usual drop down when using "new" does not contain the IUI handler classes though they are in the object library.
I am not sure if there is just some piece I am not accounting for in the code since I am using vba, but all examples seem to be for .net or C#/C++. Any help would be appreciated.
Additionally, I have no problem finding the element in question and all other pieces work fine. If you need any other pieces of the code let me know.
Edit: added set to line 3. No change in the problem though.
After two years this probably isn't relevant any more, but perhaps somebody else encounters this problem... The answer is to create a new class that implements the HandleAutomationEvent method.
Here I created a class named clsInvokeEventHandler and (importantly) set the Instancing property to PublicNotCreatable:
Option Explicit
Implements IUIAutomationEventHandler
Private Sub IUIAutomationEventHandler_HandleAutomationEvent(ByVal sender As UIAutomationClient.IUIAutomationElement, ByVal eventId As Long)
Debug.Print sender.CurrentName
End Sub
And to use it:
Sub StartInvokeHandler()
Dim oUIA As New CUIAutomation8
Dim oRoot As IUIAutomationElement
Dim InvokeHandler As clsInvokeEventHandler
Set InvokeHandler = New clsInvokeEventHandler
Set oRoot = oUIA.GetRootElement
oUIA.AddAutomationEventHandler UIA_Invoke_InvokedEventId, oRoot, TreeScope_Descendants, Nothing, InvokeHandler
End Sub

VB.net Streamreader use across different subs

I am setting streamreader to populate a list and then when I encounter a formfeed, I process each page separately. My problem is when I go to another sub the streamreader info is lost. How to I make it link across different subs?
Example is posted below:
Public Sub cmdGet()
Do Until sr_Read.EndOfStream
ClearVariables()
line = sr_Read.ReadLine
Populate_List()
ParseRecord()
Print_Output_Record()
myList01.Clear()
myList01.Add("")
Loop
end Sub
Public Sub Populate_List()
line = SR_Read.ReadLine
Do While (Mid(line, 1, 1) <> Chr(12))
myList01.Add(line)
line = SR_Read.ReadLine
Loop
End Sub
Thank you for any assistance you can provide me.
I'm betting you have a problem with what's called variable scope. Somewhere you had to declare that stream reader object... Something like this...
Dim Sr_Read As New StreamReader("flename")
You want to make sure that it is declared at the top of the class file... e.g. NOT inside any of the subs.

Ensure maintainability & testability in file-processing application

Problem
I want to refactor an old application which has grown over time and is awful to maintain/test. Basically the app needs to read an file an process it lines.
The file to be read can be compared to a CSV-file, where the first field determines the type of the line, something like this:
1,abcd,...
1,3423,...
2,"abc",...
5,test,...
Currently the application works like this (pseudo-code):
For Each line in file.getLines()
if (line.StartsWith("1,") then
' Process line of type 1
elseif (line.StartsWith("2,") then
' Process line of type 2
...
End If
Next
This obviously is a nightmare to maintain and test. Therefore I'd like refactor this whole thing and thought of doing it like this:
Create a parser for each line-type
Let each parser register itself to a handler, which will raise an event for each line
Code Idea
Handler:
Public Class ParserHandler
Public Event Parse(RepLine As ReportLine)
Public Event FileFinished()
Public Sub RaiseParse(RepLine As ReportLine)
RaiseEvent Parse(RepLine)
End Sub
Public Sub RaiseFileFinished()
RaiseEvent FileFinished()
End Sub
End Class
Parser:
Public Class FirstParser
Public Sub New(Handler As ParserHandler)
AddHandler Handler.Parse, AddressOf Parse
AddHandler Handler.FileFinished, AddressOf FileFinished
End Sub
Public Sub Parse(RepLine As ReportLine)
If Not RepLine.Type = 1 Then
Return
End If
' Process
End Sub
Private Sub FileFinished()
' Final stuff, eg. insert into DB
End Sub
End Class
Main:
Dim ParserHandler As New ParserHandler()
Dim FirstParser As New FirstParser(ParserHandler)
Dim SecondParser As New SecondParser(ParserHandler)
...
For Each line in file.getLines()
' Extract Id and construct ReportLine-object here
ParserHandler.RaiseParse(ReportLine)
Next
I think this looks way better than the original version, but I'm still not convinced that this is really the way to go. In case of testing the parsers with unit tests, I still have to create a handler first. This might be ok, but feels wrong as the parser should be testable separately (is it wrong?).
I like the use of events in this case, as not every parser needs to implement every possible event of the handler, which prevents me from just having an IParser interface.
What do you think of this approach, is it good to go? Are there any best practices/design pattern I should look into for a clean solution to this problem?

VB.net avoiding cross thread exception with extension method

Hello
I am trying to implement a solution for updating form controls without using a delegate.
I am attempting to use the 1st solution on this page:
http://www.dreamincode.net/forums/blog/143/entry-2337-handling-the-dreaded-cross-thread-exception/
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Public Module MyInvoke
<Extension()> _
Public Sub CustomInvoke(Of T As ISynchronizeInvoke)(ByVal control As T, ByVal toPerform As Action(Of T))
If control.InvokeRequired Then
control.Invoke(toPerform, New Object() {control})
toPerform(control)
End If
End Sub
End Module
The site gives this as example of how to use:
Label1.CustomInvoke(l => l.Text = "Hello World!")
But i get 'l' is not declared error.
As you can see im very new to VB or any OOP.
I can get the second solution on that page to work (using delegates) but i have quite a few things to do in this thread and it seems like i would need to write a new delegate sub for each thing, which seems wasteful.
What i need to do is select the 1st item from a combobox, update a textbox.text with the selected item, and pass the selected item to a function.
Then wait for x seconds and start again, selecting the second item.
I can get it to work in a single threaded application, but i need the interface to remain responsive.
Any help greatly appreciated.
EDIT:
OK so changing the syntax worked for the example.
However if i change it from
Label1.CustomInvoke(Sub(l) l.text = "hello world!")
(which worked just fine) to:
Dim indexnumber As Integer = 0
ComboBox1.CustomInvoke(Sub(l) l.SelectedIndex = indexnumber)
I get a cross threading error as though i didnt even use this method:
Cross-thread operation not valid: Control 'ComboBox1' accessed from a thread other than the thread it was created on.
So now im back to where i started?
Any further help very much appreciated.
Per your second issue; I think you need to add an Else:
Public Sub CustomInvoke(Of T As ISynchronizeInvoke)(ByVal control As T, ByVal toPerform As Action(Of T))
If control.InvokeRequired Then
control.Invoke(toPerform, New Object() {control})
Else
' ^^^^
toPerform(control)
End If
End Sub
You’re confusing VB and C# syntax. Your lambda is (almost, missing braces) valid C# but in VB you must write this differently:
Label1.CustomInvoke(Sub (l) l.Text = "Hello World!")
And yes, this syntax s*cks. Sorry. :-(
Label1.CustomInvoke(l => l.Text = "Hello World!")
This is C# syntax.
The VB.NET equivalent is:
Label1.CustomInvoke( Sub(l) l.Text = "Hello World!" )
... updating form controls without using a delegate...
Just FYI - A lambda expression, which is what this is using, is a form of delegate. It's just a more convenient syntax for declaring and defining delegates - but you're still using delegates here.

Runtime Error 424 Object Required

Hey so I get this error in this code:
Private Sub Request_Stuff_button_Click()
Call Main.createObjects
Call My_Control.requestStuff
End Sub
at the 'Call My_Control.requestStuff' line.
The 'Main' module looks like this:
Public My_Control As ControlObject
Public Sub createObjects()
If My_Control Is Nothing Then
Set My_Control = New ControlObject
End If
End Sub
The weirdest thing is that when I add
Dim x As Integer
x = My_Control.dummyInt
right before the line that gets me the error, x gets the correct value right before the error happens which means My_Control is definitely an object and is definitely not nothing.
This error is killing me, thanks in advance.
Thanks but that wasn't the problem, the issue was actually in the requestStuff method but the debugger was freezing on that line instead of in the method and silly me forgot to check for that.