I am trying to load dummy crystal report document on Form Load so that Crystal Report dll gets loaded in memory.
Private Sub Reports_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim swatch As New Stopwatch
swatch.Start()
Cryload()
swatch.Stop()
Label6.Text = swatch.ElapsedMilliseconds.ToString
End Sub
Private Async Function Cryload() As Task
Dim rpt As New ReportDocument
Await Task.Run(Sub() rpt.Load("Reports\Dummy.rpt"))
End Function
If I run without Crystal Report Document Load the time to load Form is 22 milliseconds.
If I run Cryload() with out Async Load time is 23746 milliseconds.
If I run Cryload() with Async/Await Load time is 14020 milliseconds.
I am sure I am missing something, is there a way to reduce the Form Load time.
Thank you
Related
can you help me i have problem with vb.net language.
I want to call crystal report but can't with the data format in gridview sent via crystalreport. with the following code:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim reports As New bpkb_1
reports.SetDataSource(ds.Tables(0))
viewermurabahah.CrystalReportViewer1.ReportSource = reports
viewermurabahah.ShowDialog()
end sub
can you give an example of how the code to call the crystal report file outside of the visual studio vb.net project file?
You can call the load method of the ReportDocument
Dim rpt As New CrystalDecisions.CrystalReports.Engine.ReportDocument
rpt.Load(<Path to your crystal report file>)
rpt.SetDataSource(<your data table>)
YouReportViewer.ReportSource = rpt
I am currently working on a VB.NET form that automatically create Word documents according to an Excel file and a few extra data asked by the form (Project Name, Customer Name, Use SQL, ...).
This procedure works fine and takes approximatelly 1 or 2 minutes to complete.
The issue is that all my script is in ButtonGenerate.Click Handler. So when the Generate button is pressed the form window is bricked and it's impossible to Cancel...
It shouldn't be in a Click handler. Opening a new thread for that long task seems better. But Multithreading isn't very familiar to me.
I tryed launching the script with
ThreadPool.QueueUserWorkItem(...
but my Generate Sub sets labels and update a Progress Bar in the main form, so I doesn't work unless I use
Me.Invoke(New MethodInvoker(Sub()
label.Text = "..."
ProgressBar.Value = 10
' ...
End Sub)
each time I need to update something on the form and I can't even retrieve any new push of a button with that (A cancel button would be nice).
This is basically my code :
Public Class TestFichesAutomation
Private Sub BtnGenerate_Click(sender As Object, e As EventArgs) Handles BtnGenerate.Click
System.Threading.ThreadPool.QueueUserWorkItem(Sub() Generate())
End Sub
Public Sub Generate()
' Check user options, retrieve Excel Data, SQL, Fill in custom classes, create Word docs (~ 1 minute)
End Sub
So How would you handle that script ? Is Threading even a good solution ?
Thanks a lot for your help ^^ and for the useful doc.
My app now open a new thread and uses 2 custom classes to act like buffers :
Private Async Sub Btn_Click(sender As Object, e As EventArgs) Handles Btn.Click
myProgress = New Progress
' a custom class just for the UI with the current task, current SQL connection status and progress value in %
_Options.ProjectName = TextBoxProjectName.Text
_Options.CustomerName = TextBoxCustomerName.Text
...
' Fill in a custom "_Options" private class to act as a buffer between the 2 thread (the user choices)
Loading = New Loading()
Me.Visible = False
Loading.Show() ' Show the Loading window (a ProgressBar and a label : inputLine)
Task.Run(Function() Generate(Progress, _Options))
Me.Visible = True
End Sub
Public Async Function Generate(ByVal myProgress As Progress, ByVal Options As Options) As Task(Of Boolean)
' DO THE LONG JOB and sometimes update the UI :
myProgress.LoadingValue = 50 ' %
myProgress.CurrentTask= "SQL query : " & ...
Me.Invoke(New MethodInvoker(Sub() UpdateLoading()))
' Check if the task has been cancelled ("Cancelled" is changed by a passvalue from the Loading window):
If myProgress.Cancelled = True Then ...
' Continue ...
End Function
Public Shared Sub UpdateLoading()
MyForm.Loading.ProgressBar.Value = myProgress.LoadingValue
MyForm.Loading.inputLine.Text = myProgress.CurrentTask
' ...
End Sub
You should look into using the Async/Await structure
if the work you need to do is CPU bound, i like using Task.Run() doc here
By making your event handler Async and having it Await the work, you prevent the UI from locking up and avoid the use of Invoke in most cases.
ex:
Private Async Sub Btn_Click(sender As Object, e As EventArgs) Handles Btn.Click
Dim Result As Object = Await Task.Run(Function() SomeFunction())
'after the task returned by Task.Run is completed, the sub will continue, thus allowing you to update the UI etc..
End Sub
For progress reporting with Async/Await you might be interested in this
i created a report and trying to load it to a reportviewer manually but not able to get it loaded .
my code
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ReportViewer1.Reset()
Dim ReportDataSource1 As Microsoft.Reporting.WinForms.ReportDataSource = New Microsoft.Reporting.WinForms.ReportDataSource
ReportDataSource1.Name = "InvoiceData_DataTable1"
ReportDataSource1.Value = New InvoiceDataTableAdapters.DataTable1TableAdapter().GetData("EBM267")
Me.ReportViewer1.LocalReport.DataSources.Clear()
Me.ReportViewer1.LocalReport.DataSources.Add(ReportDataSource1)
ReportViewer1.LocalReport.ReportEmbeddedResource = "Billmanagement.report.rdlc"
ReportViewer1.RefreshReport()
End Sub
my Dataset name is InvoiceData
DataTable1 has a parameter billno
which i am supplying for demo but not working please let me know why my report is not loading
a blank report with error is comming
"A datasource instance has not been supplied for the datasource DataSet1"
In Billmanagement.report.rdlc you are using an oject with .DataSetName property set as DataSet1: check every Table/List/Matrix in your report.
I have a small VB.Net project with link to sql using web service (SOAP).
I have to make sure that all forms are totally responsive no matter what, and it's working pretty well. My only problem is on loading the application!
The main start-up form has only single line of code:
Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Await objWebService.GetCurrentSessionsAsync
End Sub
But while this "awaitable" code is being executed the form is unresponsive, frozen and wait cursor is displayed.
Any idea on what might be causing this issue and how to handle it?
In regard to your answer, the code can be much cleaner if you don't combine different programming patterns, check this out:
Private Async Sub frmMain_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Dim res = Await GetCurrentSessionsAsync()
End Sub
Private Async Function GetCurrentSessionsAsync() As Task(Of com.services.Server)
Try
Return Await Task.Factory.
StartNew(Function() objWebService.GetCurrentSessions)
Catch ex As Exception
Glob.ErrorLog("GetCurrentSessions", ex, True)
Return New com.services.Server
End Try
End Function
References:
try-catch (C# Reference)
Async Return Types (C# and Visual Basic)
The key problem is that Async does not magically make your method asynchronous. It only lets compiler know that your method will have Await keywords, and that the code needs to be converted into a state machine. Any code that is not awaited is executed synchronously, even if the method is marked as Async. Consider the following example:
Private Async Sub Form1_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Await LongRunning1() 'opens the form, then asynchronously changes
'Text property after 2 seconds
End Sub
Private Async Function LongRunning1() As Task
Await Task.Factory.StartNew(Sub() Threading.Thread.Sleep(2000))
Me.Text = "Finished LongRunning1"
End Function
Here a long running process, Thread.Sleep as an example, is wrapped into a Task, and there is an Await keyword. It tells the compiler to wait for the statements inside the task to finish, before executing the next line. Without the Await, the Text property would be set immediately.
Now suppose you have some long running synchronous code in your Async method:
Private Async Sub Form1_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Await LongRunning2() 'synchronously waits 2 seconds, opens the form,
'then asynchronously changes Text property after 2 seconds
End Sub
Private Async Function LongRunning2() As Task
Threading.Thread.Sleep(2000)
Await LongRunning1()
Me.Text = "Finished LongRunning2"
End Function
Notice in this case it synchronously waits for the Thread.Sleep to finish, so for the end user you app appears as hanging. Bottom line is - you have to know which method calls can be long running, and wrap them into a task based await model. Otherwise you may be seeing the problem you are seeing.
If this sounds too complicated, you can fire up a background worker (.NET 2.0+), or use TPL (.NET 4.0+) to start a task. If you wish to go into lower level, threading is available since .NET 1.1. Then display some wait/progress window/overlay on top of the form/control, for which the functionality is not yet available. Check these out:
Loading data from DB asynchronously in win forms
Await async with event handler
Thanks to #PanagiotisKanavos for pointing me in the right direction.
So here what it is (I have to say that the answer of Neolisk and Panagiotis led me to the solution):
What made my loading form unresponsive is what appeared to be a bug in web services, only the first call of my web service would produce this issue. So If the first call was made after form load, on another event, I would face same problem.
To fix this, I changed the way I call my first method through web service using TaskCompletionSource variable, and calling my first method using Thread. I'll post my before/after code to be sure I delivered my fix clearly.
Before:
Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim res = Await objWebService.GetCurrentSessionsAsync
End Sub
After:
Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim res = Await GetCurrentSessionsAsync()
End Sub
Dim _tcServer As New TaskCompletionSource(Of MyProject.com.services.Server)
Private Async Function GetCurrentSessionsAsync() As Task(Of com.services.Server)
Try
Dim th As New System.Threading.Thread(AddressOf GetCurrentSessions)
th.Start()
Return Await _tcServer.Task
Catch ex As Exception
Return New MyProject.com.services.Server
End Try
End Function
Private Sub GetCurrentSessions()
Try
Dim res = objWebService.GetCurrentSessions
_tcServer.SetResult(res)
Catch ex As Exception
Glob.ErrorLog("GetCurrentSessions", ex, True)
End Try
End Sub
I hope this can help others in the future.
Thank you.
My application periodically starts console programs with process.start. I need to monitor the output of the programs in "realtime".
For example, the program writes the following text to the console:
Processing.................
Every second or so a new dot appears to let the user know the program is still processing. However,... until the programm outputs a CR/LF, I am not able to retrieve the standard output of the program (while it is still running).
What can I do to get the output in realtime for - let's say - piping it into a database for instance in VB.NET?
what about sending output into a text file and reading that file every second?
I'm gutted since I did have a prototype application at home that did something like this. I'll see if I can fetch it. In the meantime have a look at this link:
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx
It shows how to redirect the output of applications to a custom stream e.g.
Public Class Form1
Private _p As Process
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim psi As New ProcessStartInfo()
psi.FileName = "C:\mydir.bat"
psi.RedirectStandardOutput = True
psi.UseShellExecute = False
_p = New Process()
_p.Start(psi)
tmrReadConsole.Enabled = True
End Sub
Private Sub tmrReadConsole_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrReadConsole.Tick
If _p IsNot Nothing Then
txtConsoleOutput.Text = _p.StandardOutput.ReadToEnd()
End If
End Sub
End Class
The above is a webform that has a timer which is used to poll the output stream of a console and get it's content into a textbox. It doesn't quite work (hence why I want to find my other app), but you get the idea.
Hope this helps.