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.
Related
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
I've seen a few other posts about this but I seem to be confused since I've seen it done several ways and haven't gotten it correct any of the ways, so I thought I would ask specifically for my case so I can learn what I am doing wrong. After learning and switching to C# for most of my programming, VB.net seems so clunky in its syntax with a lot of things, especially lambda and "on-the-fly" functions.
I have a long running task for a football game I am working on where it generates players. Its an async method utilizing the Task.Factory.StartNew method.
Here is the pertinent code:
Private Sub CreateDraft_Click(sender As Object, e As RoutedEventArgs) Handles CreateDraft.Click
TimeIt(Sub() ReallyGenNewPlayers())
End Sub
'Uses a stopwatch to time how long it takes and sends to console.
Private Sub TimeIt(MyAction As Action)
Dim SW As New Stopwatch
SW.Start()
MyAction()
Console.WriteLine($"Total Time Generating Players: {SW.Elapsed} seconds")
SW.Stop()
End Sub
Private Async Sub GenNewPlayersASync()
Dim myvalue = 0
'Generate the Players on an Async Thread
Dim x As Integer
For i As Integer = 1 To NumPlayers
x = i 'avoids issue with using the iteration variable inside the delegate
CollegePlayers.GenDraftPlayers(i, MyDraft, DraftDT, DraftClass, PosCount)
'Prog_ValueChanged(DBNull.Value, New RoutedPropertyChangedEventArgs(Of Double))
'Calls a delegate to update the progress bar to avoid having the variable locked by the background thread
Dispatcher.Invoke(Sub()
worker.ReportProgress((x / NumPlayers) * 100)
End Sub)
Next i
End Sub
'Creates a task to run the player generation code and wait til its finished
Private Sub ReallyGenNewPlayers()
Dim mytask = Task.Factory.StartNew(Sub() GenNewPlayersASync())
Task.WaitAll(mytask)
End Sub
So here is what I would like to do:
I have a progressbar I created in XAML that has a Progress_Changed Event. This is what I have for it so far based on another post, but the issue is when I have to call the function inside GenNewPlayersAsync() where it wants a RoutedPropertyChangeEventArgs as a double which I'm not exactly sure what to do...I tried creating one using .New(old value, new value) but that didn't work either and threw an error.
Public Async Sub Prog_ValueChanged(sender As Object, e As RoutedPropertyChangedEventArgs(Of Double))
Dim progress = New Progress(Of Integer)(Function(percent)
Prog.Value = e.NewValue
Return Prog.Value
End Function)
Await Task.Run(Sub() DoProcessing(progress))
End Sub
Public Sub DoProcessing(progress As IProgress(Of Integer))
Dim i As Integer = 0
While i <> 100
Thread.Sleep(100)
' CPU-bound work
If progress IsNot Nothing Then
progress.Report(i)
End If
End While
End Sub
I would like for the progressbar to be bound to an INotifyChanged Property and update itself automatically when the value gets changed. None of it seems to be working. The UI is still unresponsive and when I set different parts to ASync, I start getting Exceptions where it appears certain parts of the generation algorithm aren't working as they are returning null...very confused with all of this, and I am sure the answer is probably pretty simple...
If you guys could give several examples of different ways to get this to work so I can learn different methods and maybe state the pros and cons of the method I would greatly appreciate it...
So my issue may sound familiar, I simply want to update a progress bar concurrently with the data that is being processed in my program.
I have two windows: StartupWindow and UpdateWindow.
The Application begins by creating the startup window, the user will push a button to open the UpdateWindow. The following is the code for the button:
Private Sub btnUpdateClick(sender As Object, e As RoutedEventArgs) Handles btnUpdate.Click
Dim updateWindow As New UpdateWindow
updateWindow.ShowDialog()
btnUpdate.IsEnabled = False
End Sub
With this code I got the error most other people do: "The calling thread cannot access this object because a different thread owns it."
Private Sub updateDevice()
Dim currPercent As Integer
currPercent = ((sentPackets / totalPacketsToWrite) * 100)
progressLabel.content = currPercent.ToString + "%"
pb.Maximum = totalPacketsToWrite
pb.Value = sentPackets
If sentPackets < totalPacketsToWrite Then
'....update....
Else
MsgBox("Device now has update stored on flash!")
'...close everything up
End If
End Sub
Here are the three things I have tried so far:
Use Invoke/Dispatcher/Delegate to try and seem to only be able to put the update in a different thread's queue? Can't seem to pause other the other threads to update the UI either...
Implement the BackgroundWorker Class and use report progress from it, this worked but I could only update the progress bar under bw.DoWork I make a lot of calls and have responses from external devices so it would be difficult to put all my code under one function.
I read somewhere that since this was the second window created (called from the original) I would have issues with it. So I took someone's solution and tried to create and entire new thread when the 'update' button was pressed ie.:
Something to note is that I added a 'cancel' button:
Private Sub buttonStart_Click(sender As Object, e As RoutedEventArgs) Handles btnStart.Click
btnStart.IsEnabled = False
btnStart.Visibility = Windows.Visibility.Hidden
btnCancel.IsEnabled = True
btnCancel.Visibility = Windows.Visibility.Visible
beginUpdate()
End Sub
Private Sub buttonCancel_Click(sender As Object, e As RoutedEventArgs) Handles btnCancel.Click
btnStart.IsEnabled = True
btnStart.Visibility = Windows.Visibility.Visible
btnCancel.IsEnabled = False
btnCancel.Visibility = Windows.Visibility.Hidden
'TODO MAKE IT CANCEL
End Sub
And every time I clicked the update/cancel button the progress bar would update. Every time I pressed the button it refreshed the progress bar to the current completion. I'm quite puzzled, I am able to update user interfaces if it is just one window... but if the user pushes a button to call a new window I cannot update anything in the second window. Any suggestions?
EDIT:
I ended up making global variables that updated in my long code. Than ran backgroundworker before I did anything else and it ran asynchronous to my process, updating the progress bar:
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
While finished = False
Threading.Thread.Sleep(50)
bw.ReportProgress(currPercent)
End While
End Sub
The start of my code was simple - like so:
Private Sub buttonStart_Click(sender As Object, e As RoutedEventArgs) Handles btnStart.Click
bw.RunWorkerAsync()
beginUpdate()
End Sub
First things first... get the ProgressBar working: For this part, please read my answer to the Progress Bar update from Background worker stalling question here on Stack Overflow. Now, let's assume that you've got the basic update of a ProgressBar working... next, you want to be able to cancel the work. It is a simple matter to update the DowWork method accordingly:
private void DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= 100; i++)
{
if (IsCancelled) break; // cancellation check
Thread.Sleep(100); // long running process
backgroundWorker.ReportProgress(i);
}
}
So all you need to do to cancel the long running process and the ProgressBar update is to set the IsCancelled property to true.
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
We have an issue in our Silverlight application which uses WCF and Entity Framework, where we need to trap the event whenever a user shuts down the application by closing the web page or the browser instead of closing the silverlight application. This is in order to verify if any changes have been made, in which case we would ask the user if he wants to save before leaving.
We were able to accomplish the part which consists in trapping the closing of the web page: we wrote some code in the application object that have the web page call a method in the silverlight application object. The problem starts when in this method, we do an asynchroneous call to the Web Service to verify if changes have occured (IsDirty). We are using a DispatcherTimer to check for the return of the asynchroneous call. The problem is that the asynchroneous call never completes (in debug mode, it never ends up stepping into the _BfrServ_Customer_IsDirtyCompleted method), while it used to work fine before we added this new functionality.
You will find belowthe code we are using.
I am new to writing timers in combination with asynchroneous call so I may be doing something wrong but I cannot figure out what. I tried other things also but we without any success..
====================== CODE ==============================================
''# Code in the application object
Public Sub New()
InitializeComponent()
RegisterOnBeforeUnload()
_DispatcherTimer.Interval = New TimeSpan(0, 0, 0, 0, 500)
End Sub
Public Sub RegisterOnBeforeUnload()
''# Register Silverlight object for availability in Javascript.
Const scriptableObjectName As String = "Bridge"
HtmlPage.RegisterScriptableObject(scriptableObjectName, Me)
''# Start listening to Javascript event.
Dim pluginName As String = HtmlPage.Plugin.Id
HtmlPage.Window.Eval(String.Format("window.onbeforeunload = function () {{ var slApp = document.getElementById('{0}'); var result = slApp.Content.{1}.OnBeforeUnload(); if(result.length > 0)return result;}}", pluginName, scriptableObjectName))
End Sub
Public Function OnBeforeUnload() As String
Dim userControls As List(Of UserControl) = New List(Of UserControl)
Dim test As Boolean = True
If CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0).GetType().Name = "MainPage" Then
If Not CType(CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0), MainPage).FindName("Tab") Is Nothing Then
If CType(CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0), MainPage).FindName("Tab").Items.Count >= 1 Then
For Each item As TabItem In CType(CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0), MainPage).Tab.Items
If item.Content.GetType().Name = "CustomerDetailUI"
_Item = item
WaitHandle = New AutoResetEvent(False)
DoAsyncCall()
Exit
End If
Next
End If
End If
End If
If _IsDirty = True Then
Return "Do you want to save before leaving."
Else
Return String.Empty
End If
End Function
Private Sub DoAsyncCall()
_Item.Content.CheckForIsDirty(WaitHandle) ''# This code resides in the CustomerDetailUI UserControl - see below for the code
End Sub
Private Sub _DispatcherTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles _DispatcherTimer.Tick
If Not _Item.Content._IsDirtyCompleted = True Then
Exit Sub
End If
_DispatcherTimerRunning = False
_DispatcherTimer.Stop()
ProcessAsyncCallResult()
End Sub
Private Sub ProcessAsyncCallResult()
_IsDirty = _Item.Content._IsDirty
End Sub
''# CustomerDetailUI code
Public Sub CheckForIsDirty(ByVal myAutoResetEvent As AutoResetEvent)
_AutoResetEvent = myAutoResetEvent
_BfrServ.Customer_IsDirtyAsync(_Customer) ''# This method initiates asynchroneous call to the web service - all the details are not shown here
_AutoResetEvent.WaitOne()
End Sub
Private Sub _BfrServ_Customer_IsDirtyCompleted(ByVal sender As Object, ByVal e As BFRService.Customer_IsDirtyCompletedEventArgs) Handles _BfrServ.Customer_IsDirtyCompleted
If _IsDirtyFromRefesh Then
_IsDirtyFromRefesh = False
If e.Result = True Then
Me.Confirm("This customer has been modified. Are you sure you want to refresh your data ? " & vbNewLine & " Your changes will be lost.", "Yes", "No", Message.CheckIsDirtyRefresh)
End If
Busy.IsBusy = False
Else
If e.Result = True Then
_IsDirty = True
Me.Confirm("This customer has been modified. Would you like to save?", "Yes", "No", Message.CheckIsDirty)
Else
Me.Tab.Items.Remove(Me.Tab.SelectedItem)
Busy.IsBusy = False
End If
End If
_IsDirtyCompleted = True
_AutoResetEvent.Set()
End Sub
Your problem is that the DispatchTimer is trying to execute code on the same thread that you are blocking with the Wait. Hence it can't deliver the tick.
I'm not sure I'm clear why you need the timer at all. Why not simply block the UI thread (as in fact you already doing) directly in the call to OnBeforeUnload. Then have the asynchronous callback function set the wait handle after it has assigned the value of _IsDirty.
Follow the Wait with your message boxes.