What is the VB syntax to add a handler using a delegate? - wpf

In a WPF project:
I believe this C# line of code is simply adding a handler to the User Interface object and forcing the parameter to 'false' when the handler is invoked.
item.MouseDoubleClick += delegate { otherMethod1(false); };
In adding VB handlers without parameters am I correct this would be the proper syntax?
AddHandler item.MouseDoubleClick AddressOf otherMethod2
How do I express in VB a handler with parameters as in the first line above?

Try this:
AddHandler item.MouseDoubleClick, Sub(sender As Object, e As MouseButtonEventArgs)
otherMethod1(False)
End Sub

Related

Updating UI from another thread with VB in WPF

I am trying to use a timer to scan my Xbox 360 controller. But I cannot directly update my UI like the code I wrote below.
I would get a exception when I try to run this code.
An exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll but was not handled in user code
Additional information: The calling thread cannot access this object because a different thread owns it.
XButton is a radiobutton on the GUI that I want to toggle.
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Input
Imports System.Timers
Imports System.Windows.Threading
Public Class XboxControllerStatus
Friend WithEvents Timer1 As Timer
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Elapsed
Dim currentState As GamePadState = GamePad.GetState(PlayerIndex.One)
If currentState.IsConnected Then
If currentState.Buttons.X.Pressed Then
XButton.IsChecked = True
Else
XButton.IsChecked = False
End If
End If
End Sub
End Class
This works for me, all the time
Control.Invoke(sub()
'Put code here
End Sub)
First you need to set up a delegate
Delegate Sub SetCheckBoxCallback(ByVal value As Boolean)
Friend Sub SetCheckBox(ByVal value As Boolean)
XButton.IsChecked = value
End Sub
after that all you need to do is call the following code from within your timer to invoke it:
Dim DesiredValue as Boolean = True
Me.Dispatcher.Invoke(New SetCheckboxCallback(AddressOf SetCheckbox), New
Object() {DesiredValue})

How do I use the Trim Function

I'm converting a web project from VB to C#, and I can't figure out how to implement the trim function. Do I have to write a specific function, or is there a way to use it in the context of my project? Here is the functional VB code I'm trying to convert. If you need more details, please ask.
Protected Sub ButtonSetup(ByVal Dr As DataRow, ByVal Btn As Button)
Btn.Visible = True
Btn.Text = Dr("Floor_Name").ToString.Trim()
Btn.CommandArgument = Dr("Floor_File").ToString.Trim()
Btn.CssClass = "GreyButtonStyle"
AddHandler Btn.Click, AddressOf Me.Schematic_Button_Click
End Sub
Indexer
C# uses the square bracket[] to access element of an indexer instead of parentheses()
Event Handler
AddHandler and AddressOf are both VB keyword. In order to add an handler to an event, use the += operator with the event as left operand and handler as the right operand.
protected void ButtonSetup(DataRow row, Button button)
{
button.Visible = true;
button.Text = row["Floor_Name"].ToString().Trim();
button.CommandArgument = row["Floor_Name"].ToString().Trim();
button.CssClass = "GreyButtonStyle";
button.Click += Schematic_Button_Click;
}
I work in C# and your code is VB, but it looks like you are just calling it wrong.
You have
Btn.Text = Dr("Floor_Name").ToString.Trim()
Which accesses the ToString method of the data row and calls Trim() on it. You aren't actually calling ToString. Change it to
Btn.Text = Dr("Floor_Name").ToString().Trim()
and it should work.

vb.net can't remove handler

I got this piece for moving an element around on a canvas
Private p As Point
Private Sub moveHandler() Handles Me.MouseDown
p = Mouse.GetPosition(Me)
AddHandler canvasRef.MouseMove, AddressOf moveLoop
End Sub
Private Sub moveLoop()
If Mouse.LeftButton = MouseButtonState.Pressed Then
Dim c As Point = Mouse.GetPosition(canvasRef)
Canvas.SetLeft(Me, c.X - p.X)
Canvas.SetTop(Me, c.Y - p.Y)
Else
RemoveHandler canvasRef.MouseMove, AddressOf moveLoop
End If
End Sub
It underlines the removehandler and says something like "The addressof expression has no effect because it requires a relaxed something something, make delegate and remove that instead!"
Makes no sense to me.
That's because the signature of the moveLoop method doesn't match the signature of the MouseEventHandler delegate. Because VB.NET is so lax, it allows you to add it as a handler for the event, by internally creating an anonymous method with the required parameters that calls your handler. But when you try to remove the handler, it doesn't work because the anonymous method created before is no longer accessible...
The easiest fix is to change the signature of your method so that it matches the signature of the delegate:
Private Sub moveLoop(ByVal sender As Object, ByVal e As MouseEventArgs)
Another option is to store a reference to the handler as shown in keyboardP's answer.
Create a new EventHandler and then add and remove like so
Dim moveLoopHandler As New EventHandler(AddressOf moveLoop)
AddHandler canvasRef.MouseMove, moveLoopHandler
RemoveHandler canvasRef.MouseMove, moveLoopHandler

Accessing the UI thread to change dependancy properties in WPF

I'm trying to update a dependancy property in VB.Net 4.0 inside of an Async callback. I feel like I am doing this correctly but I'm still getting the "The calling thread cannot access this object because a different thread owns it." error. Does someone see a better way of using delegates in VB.Net 4.0?
Private WithEvents myObj as CallingObject
Private Delegate Sub MyErrorDel(ByVal strError as string)
Public Property ErrorMessage As String
Get
Return CStr(GetValue(ErrorMessageProperty))
End Get
Set(ByVal value As String)
SetValue(ErrorMessageProperty, value)
End Set
End Property
Private Sub MySub()
myObj.CallFuncAsync()
End Sub
Private Sub DisplayError(ByVal strError as String)
'Set Dependancy Property value Bound to UI Textbox
ErrorMessage = strError
End Sub
Private Sub myObj_CallFuncCompleted(Byval sender as Object, ByVal e as CallFuncEventArgs)
'Call delegate and pass in error string as argument
Dim delError as MyErrorDel
delError = New MyErrorDel(AddressOf DisplayError)
delError("An error occured")
Me.Dispatcher.Invoke(delError, System.Windows.Threading.DispatcherPriority.Normal, Nothing)
End Sub
Whenever ErrorMessage gets set inside of DisplayError an exception gets thrown, even though I am using the dispatcher to call DisplayError.
If anyone see any issues with the way I am trying to access Dependancy Properties from a async callback I would really appreciate the feedback.
Thanks for the help!
Oh and I'm pretty new at blogging about code issues. Any suggestions about how to better formulate this question would be welcome as well.
The problem might be that at the call to Me... you are already accessing an object owned by another thread, try to store a reference to the dispatcher beforehand or possibly use Application.Current.Dispatcher.
Since you didn't indicate the offending line, I suspect the problem here is that you're invokng your delegate in the line delError("An error occured") rather than waiting until you get to the dispatcher. Consider changing your CallFuncCompeted implementation to
Me.Dispatcher.Invoke(AddressOf DisplayError, "An error occureed")

asynchronous threads and anonymous delegates

Ok, now I can use 2 techniques to launch my threads: Dispatcher and BackgroundWorker.
Dispatcher:
' I launch the asynchronous process
Dim a As New Action(AddressOf operazioneLunga)
a.BeginInvoke(Nothing, Nothing)
' I update the GUI passing some parameters
Dim a As New Action(Of Integer, String)(AddressOf aggiorna_UI)
Me.Dispatcher.BeginInvoke(DispatcherPriority.Normal, a, 5, "pippo")
BackgroundWorker:
Private bw As BackgroundWorker = Nothing
Private Sub initial()
bw = New BackgroundWorker
AddHandler bw.DoWork, AddressOf longOp
AddHandler bw.RunWorkerCompleted, AddressOf endBGW
bw.RunWorkerAsync ()
End Sub
Private Sub longOp(ByVal sender As Object, ByVal e As DoWorkEventArgs)
Dim l As List(Of miaClasse2) = <Long Operation ...>
e.Result = l
End Sub
Private Sub endBGW(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
Dim l As List(Of miaClasse2) = e.Result
Dim be As BindingExpression = BindingOperations.GetBindingExpression(mioDatagrid, DataGrid.ItemsSourceProperty)
Dim m As miaClasse1 = DirectCast(be.DataItem, miaClasse1)
m.GetData (l)
mioDatagrid.UpdateLayout()
mioDatagrid.ScrollIntoView (mioDatagrid.Items(0))
RemoveHandler bw.DoWork, AddressOf massiccia
RemoveHandler bw.RunWorkerCompleted, AddressOf fineBGW
bw.Dispose()
End Sub
I don't know what is better, but I think I'll use BackgroundWorker, because I suppose there are other argouments about Dispatcher I have to know and I don't feel safe.
Pileggi
My previous post:
Hi everyone!
My application is in WPF / Vb framework 3.5 SP1. I need to execute some methods on asynchronous threads. I know this way:
Private Delegate Sub dMassiccia()
Private Delegate Sub dAggiornaUI()
Private Sub iniziale()
Dim massicciaTemp As New dMassiccia(AddressOf massiccia)
massicciaTemp.BeginInvoke(Nothing, Nothing)
End Sub
Private Sub massiccia()
'long operations...
Me.Dispatcher.BeginInvoke(DispatcherPriority.Normal, _
New dAggiornaUI(AddressOf aggiornaUI))
End Sub
Private Sub aggiornaUI()
'update the UI...
End Sub
But in this way I have to declare a delegate for every mothod I want to launch on an asynchronous thread, and it's very uncomfortable. I have a lot of method to launch in this way. I know there are the anonymous delegates, but I don't know how to use them in this case.
Can you help me?
Pileggi
PS. Other information: in this moment I don't need to lookup the status of the process launched in the asynchronous thread. The long operations are some requests to a webservice that can take some seconds every time. There is no problem for the number of threads, because I limit the possibilities for the user to start new threads until one of them is finished. I need the asyncronous threads, among other reasons, because I don't wont to block the application, I want to replace the mouse cursor with a user-control, etc..
What is it that you're trying to do, that requires you to launch all of these threads? It looks like you're creating the secondary thread just to be able to do GUI updates.
First of all, if you have to create a lot of threads, then you run the risk of running out of available threads pretty quickly. I thought the max was only 64, but the documentation says 250 per process, and it's also settable via GetMaxThreads and SetMaxThreads. Regardless, you need to decide if using the ThreadPool threads (which is what's used when you use BeginInvoke/EndInvoke) is appropriate for you.
How long do your GUI updates take? Are they going to run the entire duration of your application? Can you use a regular thread instead? Look into using a BackgroundWorker for GUI updates if you just need to update status information periodically. In some cases, even DispatcherTimer might do the trick. It just depends on what you want to do.
You also don't show all of your code, but in what's posted, EndInvoke is not called. If you do this and end up throwing an exception, you won't be able to catch it and handle the error properly.

Resources