Form Loads slowly in vb.net - vb.net

I am currently working in ERP project on vb.net. I want to load product data in a textbox on form load. I am using autocomplete method but having a data of around 26000 the form loads slowly for 4 mins. Is there any way to avoid this or is there any way to call this function in background when the application starts?
This is my autocomplete textbox code. It works fine but it hangs alot as of the data is so large.
Private Sub pn()
Try
con = Class1.dbconn
Dim dt As New DataTable
Dim ds As New DataSet
ds.Tables.Add(dt)
Dim da As New SqlDataAdapter("select [Part Name] from
Part_Master_Download$", con)
da.Fill(dt)
Dim r As DataRow
TextBox9.AutoCompleteCustomSource.Clear()
For Each r In dt.Rows
TextBox9.AutoCompleteCustomSource.Add(r.Item(0).ToString)
Next
con.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
the properties of the textbox should be set to true for autocompletetextbox

Don't populate the AutoCompleteCustomSource in a loop. Populate an array first and then load the list in one go with a single call to AddRange:
Dim items = dt.Rows.Cast(Of DataRow)().
Select(Function(row) CStr(row(0)).
ToArray()
TextBox9.AutoCompleteCustomSource.AddRange(items)
You should find that that speeds things up considerably. If there's still a problem with performance, we can look a bit further.
EDIT: To prove my point, I just tested the following code:
Public Class Form1
Private timer As Stopwatch
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
timer = Stopwatch.StartNew()
Dim rng As New Random
Dim a = Convert.ToInt32("a"c)
Dim z = Convert.ToInt32("z"c)
Dim items = Enumerable.Range(1, 26000).Select(Function(n) Convert.ToChar(rng.Next(a, z + 1)).ToString())
For Each item In items
TextBox1.AutoCompleteCustomSource.Add(item)
Next
End Sub
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
MessageBox.Show(timer.Elapsed.ToString())
End Sub
End Class
and the message displayed "00:03:08.3167858", i.e. just over three minutes to load the list. I then changed the Load event handler to this:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
timer = Stopwatch.StartNew()
Dim rng As New Random
Dim a = Convert.ToInt32("a"c)
Dim z = Convert.ToInt32("z"c)
Dim items = Enumerable.Range(1, 26000).Select(Function(n) Convert.ToChar(rng.Next(a, z + 1)).ToString())
TextBox1.AutoCompleteCustomSource.AddRange(items.ToArray())
End Sub
so a single call to AddRange instead of calling Add in a loop, and the message was "00:00:00.0557427", i.e. just under 56 milliseconds. Is that better?

You can use paging to control the amount of returned data. Check this link for detailed examples.
Another way is to use (Task Async and await) so you won't lock your UI.
Here is a few last suggestions not related directly to the question but might help clean the code a bit:
you can skip the dataset and use the datatable directly, you don't need it for just one table.
Bind your results in the datatable to a datagridview or a combobox instead of iterating through your results and filling a textbox.
cheers

Related

OnSelectedIndexChanged no working in aspx Page

i have this dropdownlist in my page
<asp:DropDownList ID="ddlselectTaxas" runat="server" AutoPostBack="True" CssClass="form-control" OnSelectedIndexChanged="ddlselectTaxas_SelectedIndexChanged"
EnableViewState="True" ViewStateMode="Enabled"></asp:DropDownList>
and this is the function in the vb file
Public Sub ddlselectTaxas_SelectedIndexChanged(sender As Object, e As EventArgs)
taxas.TryGetValue(ddlselectTaxas.SelectedItem.Text, valorTxt.Text)
valorTxt.Text = valorTxt.Text.Substring(0, valorTxt.Text.Length - 2)
End Sub
I want to change the value of a textbox (valorTxt) when I select a diferent value in the dropdownlist, but the function is not firing. I dont know why, i have zero experience with VB and asp pages. I apreciate your help. thanks in advance.
EDIT
here is the full code of the page
Public Class Emitir
Inherits System.Web.UI.Page
Public taxas As New Dictionary(Of String, String)
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
CarregaValores()
valorTxt.ReadOnly = True
End If
End Sub
Private Sub CarregaValores()
Dim dt As DataTable
Dim objAcesso As New AcessoBD
Dim consulta As String = "SELECT TE.COD_TAXA, TE.DESC_TAXA, TV.VL_TAXA FROM TAXAS_EXPEDIENTE TE JOIN TAXAS_EXPEDIENTE_VALOR TV ON TE.COD_TAXA = TV.COD_TAXA"
dt = objAcesso.DataTable(consulta, CommandType.Text)
For Each linha As DataRow In dt.Rows
taxas.Add(linha.ItemArray(1), linha.ItemArray(2))
Next
valorTxt.Text = dt.Rows.Item(0).ItemArray(2)
valorTxt.Text = valorTxt.Text.Substring(0, valorTxt.Text.Length - 2)
ddlselectTaxas.DataTextField = "DESC_TAXA"
ddlselectTaxas.DataValueField = "COD_TAXA"
ddlselectTaxas.DataSource = dt
ddlselectTaxas.DataBind()
End Sub
Protected Sub ddlselectTaxas_SelectedIndexChanged(sender As Object, e As EventArgs)
taxas.TryGetValue(ddlselectTaxas.SelectedItem.Text, valorTxt.Text)
valorTxt.Text = valorTxt.Text.Substring(0, valorTxt.Text.Length - 2)
End Sub
End Class
You don't show your code to load up the drop list.
Remember, your page load code fires EVERY time on post back.
So, if in code on page load, you load up the drop list? You need to do this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadData()
LoadCal()
End If
End Sub
Sub LoadData()
Dim cmdSQL As New SqlCommand(
"SELECT ID,(FirstName + ' ' + LastName) as EmpName
FROM Employee ORDER BY FirstName")
lstEmployee.DataSource = MyRstP(cmdSQL)
lstEmployee.DataBind()
End Sub
Function MyRstP(cmdSQL As SqlCommand) As DataTable
Dim rstData As New DataTable
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL
cmdSQL.Connection = conn
conn.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
Now, in above, I was using a listbox, but they work the same as a drop down list (combo box).
but, if you do NOT place the loading up of data inside of the If Not IsPostBack?
Then what happens is you select a drop down, and say click on a button (or in your case autopostback = true, then the page load FIRES FIRST and THEN your code runs!!!
and, if your code re-loads the drop list? Then your selection is lost!!!
So, for just about ANY page you create, ALWAYS, but always use the is postback code stub in on-load - and thus your loading of controls data ONLY occurs one time. Since if you re-load every time, then you lose your changes.
Well, I am not sure of what was happening, but I remade my page and it is working now. something was blocking the event. Thanks for your help.

VB.NET DataSet table data empty

I'm trying to use the dataset for a report, but the data is gone when I try to use it. Here is my code for the most part:
Variables:
Dim ResultsDataView As DataView
Dim ResultsDataSet As New DataSet
Dim ResultsTable As New DataTable
Dim SQLQuery As String
Search:
This is where a datagrid is populated in the main view. The data shows up perfectly.
Private Sub Search(Optional ByVal Bind As Boolean = True, Optional ByVal SearchType As String = "", Optional ByVal SearchButton As String = "")
Dim SQLQuery As String
Dim ResultsDataSet
Dim LabelText As String
Dim MultiBudgetCenter As Integer = 0
SQLQuery = "A long and detailed SQL query that grabs N rows with 7 columns"
ResultsDataSet = RunQuery(SQLQuery)
ResultsTable = ResultsDataSet.Tables(0)
For Each row As DataRow In ResultsTable.Rows
For Each item In row.ItemArray
sb.Append(item.ToString + ","c)
Response.Write(item.ToString + "\n")
Response.Write(vbNewLine)
Next
sb.Append(vbCr & vbLf)
Next
'Response.End()
If Bind Then
BindData(ResultsDataSet)
End If
End Sub
Binding Data:
I think this is a cause in the issue.
Private Sub BindData(ByVal InputDataSet As DataSet)
ResultsDataView = InputDataSet.Tables("Results").DefaultView
ResultsDataView.Sort = ViewState("SortExpression").ToString()
ResultsGridView.DataSource = ResultsDataView
ResultsGridView.DataBind()
End Sub
Reporting action:
This is where I am trying to use the table data. But it is showing as nothing.
Protected Sub ReportButton_Click(sender As Object, e As EventArgs) Handles ReportButton.Click
For Each row As DataRow In ResultsTable.Rows
For Each item In row.ItemArray
Response.Write(item.ToString)
Next
Next
End Sub
The reason I'm trying to loop through this data is to both display the data in a gridview on the main view as well as export the data to CSV. If there is a different way to export a SQL query to CSV, I'm open to any suggestions.
There has to be something I can do to get the data from the SQL query to persist through the ReportButton_Click method. I've tried copying the datatable, I've tried global variables, I've tried different methods of looping through the dataset. What am I missing?!
Thank you all in advance.
EDIT
Here is the Page_Load:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Page.IsPostBack Then
'set focus to postback control
Dim x As String = GetPostBackControlName(Page)
If Len(x) > 0 Then
x = x.Replace("$", "_")
SetFocus(x)
End If
End If
If Not IsPostBack Then
ResultsGridView.AllowPaging = False
'Enable Gridview sorting
ResultsGridView.AllowSorting = True
'Initialize the sorting expression
ViewState("SortExpression") = "ID DESC"
'Populate the Gridview
Search()
End If
End Sub
In your search function add this line after the ResultsTable setting
ResultsTable = ResultsDataSet.Tables(0)
Session("LastSearch") = ResultsTable
Then in your report click event handler recover your data from the Session variable
Protected Sub ReportButton_Click(sender As Object, e As EventArgs) Handles ReportButton.Click
ResultsTable = DirectCast(Session("LastSearch"), DataTable)
For Each row As DataRow In ResultsTable.Rows
For Each item In row.ItemArray
Response.Write(item.ToString)
Next
Next
End Sub
You need to read about ASP.NET Life Cycle and understand that every time ASP.NET calls your methods it creates a new instance of your Page class. Of course this means that global page variables in ASP.NET are not very useful.
Also consider to read about that Session object and not misuse it.
What is the difference between SessionState and ViewState?

Making a Datatable's content appear in a DataGridView

I am continuing my rewrite of an old VB6 into .Net as part of my .Net learning. I have managed to read a CSV file into a Datatable, and I can view it has populated properly using the 'datatable visualiser' when I look at 'dt', but it doesn't seem to populate the DataGridView control I am trying to tie it to. I have spent a couple of hours browsing other threads and trying things, but I cannot see what I am doing wrong. The DataGridView is on another form in the App, and I am reading the CSV file (a config file of sorts) from the main MDI form. When I show the child form containing the DataGridView it is always empty (it actually seems to have added the two datatable rows, but their content is all blank).
Public dt As New DataTable
Public ThisFilename As String = "c:\SitesDB.cfg"
Private Sub GetSitesDB()
Dim sr As New IO.StreamReader(ThisFilename)
Dim newline() As String = sr.ReadLine.Split(","c)
dt.Columns.AddRange({New DataColumn(newline(0)), New DataColumn(newline(1)), New DataColumn(newline(2)), New DataColumn(newline(3)),
New DataColumn(newline(4)), New DataColumn(newline(5)), New DataColumn(newline(6)), New DataColumn(newline(7)), New DataColumn(newline(8)),
New DataColumn(newline(9)), New DataColumn(newline(10)), New DataColumn(newline(11))})
While (Not sr.EndOfStream)
newline = sr.ReadLine.Split(","c)
Dim newrow As DataRow = dt.NewRow
newrow.ItemArray = {newline(0), newline(1), newline(2), newline(3), newline(4), newline(5), newline(6), newline(7), newline(8), newline(9), newline(10), newline(11)}
dt.Rows.Add(newrow)
End While
Form1.DataGridView1.DataSource = dt ' data can be seen here using datatable visualiser hovering over 'dt'
End Sub
Private Sub ToolStripButton1_Click(sender As Object, e As EventArgs) Handles ToolStripButton1.Click
Form1.Show()
End Sub
I have tried refreshing the DataGridView, to no avail. I am wondering if its something to do with Form1.Show() being actioned after the datatable is tied to the DataGridView?
But the following didn't help
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' chkBit.Checked = False
' Dim cfgtext As String : cfgtext = ""
DataGridView1.DataSource = NAMS.dt
End Sub

Reading txt file line by line in DataGrid View

I'm completely new to VB.net and have been given a homework assignment. I need to be able to read certain lines and display them in a DataGridView. I have been able to link my .txt file to the DGV however it reads the whole file as opposed to the specific line. I have 4 buttons: btn1, btn2, btn3, btn4. I want each button to show the respective lines in the text file. After researching on-line for the past week I'm still stuck. If anyone could help me I would really appreciate it.
Text File ("database.txt")
(Line1) c1 c2 c3
(Line2) one 1-1 1-2
(Line3) two 2-2 2-3
(Line4) three 3-2 3-3
(Line5) four 4-2 4-3
Public Class Form1
Private Sub btn1_Click(sender As Object, e As EventArgs) Handles btn1.Click
Dim lines = (From line In IO.File.ReadAllLines("database.txt") _
Select line.Split(CChar(vbTab))).ToArray
For x As Integer = 0 To lines(0).GetUpperBound(0)
DataGridView1.Columns.Add(lines(0)(x), lines(0)(x))
Next
For x As Integer = 1 To lines.GetUpperBound(0)
DataGridView1.Rows.Add(lines(x))
Next
End Sub
End Class
You did not describe the result you get, so I cannot tell what's wrong right now, as I am not on a computer and usually use c++/cli (visual c++). If I have to make a guess, I would say that you fill each file row into one DGV row, but you want just 1 row, not all. Correct?
Anyway, here are some suggestions:
Do you have to read the file on each button click? If not, I would read it once, store the content and fill into the DGV when desired.
Debug your code! Set a breakpoint at the start of the function, step over the code lines, check the variable content.
Split up the code line dim lines into 3 or more separate lines to make it more readable. Also helps at debugging.
I made following assumptions based on what you had in your question:
First line of the file was the column names
The (Line#) was just there for reference and isn't in the actual file
The number in the button name (btn#) was the row index that should be displayed in the DGV
I added a new button to the form that loads the data from the text file, parses it to a datatable and sets the DataGridView1.DataSource to that DataTable. The second method then creates a new datatable and imports the specified row from the main datatable and shows it in the DGV. Of course many will say you should use a DataView with a DataView.RowFilter for this rather than creating a new datatable, however this way works just the same.
Private txtDataTable As DataTable
Private Sub loadFileBtn_Click(sender As Object, e As EventArgs) Handles loadFileBtn.Click
txtDataTable = New DataTable("txtContents")
Dim txtContents As String()
Try
txtContents = IO.File.ReadAllLines("C:\StackOverflow\database.txt")
Catch ex As Exception
MsgBox(ex.Message)
Return
End Try
Dim txtLines As New List(Of String())
txtContents.ToList().ForEach(Sub(x) txtLines.Add(x.Split(CChar(vbTab))))
If txtLines.Count > 0 Then
txtLines.Item(0).ToList.ForEach(Sub(x) txtDataTable.Columns.Add(New DataColumn(x.ToString)))
txtLines.RemoveAt(0)
End If
If txtLines.Count > 0 Then
txtLines.ToList.ForEach(Sub(x) txtDataTable.Rows.Add(x.ToArray))
End If
DataGridView1.DataSource = txtDataTable
End Sub
Private Sub btn_Click(sender As Object, e As EventArgs) Handles btn1.Click, btn2.Click, btn3.Click, btn4.Click
If txtDataTable Is Nothing Then Return
Dim rowIndex As Integer
If Integer.TryParse(DirectCast(sender, Button).Name.Replace("btn", String.Empty), rowIndex) Then
rowIndex -= 1
Else
Return
End If
Dim TempTable As DataTable = txtDataTable.Clone
If rowIndex < txtDataTable.Rows.Count Then
TempTable.ImportRow(txtDataTable.Rows(rowIndex))
End If
DataGridView1.DataSource = TempTable
End Sub

WP7 - Updating a listbox

I've finally got around to starting windows phone dev. I'm not very good at it yet, but anyway, I hope you guys understand what I want to do here.
From what I've learnt from other programmers, an ObservableCollection can be updated in live time whilst it is databound to an object, such as a listbox. All changes to the ObservableCollection will cause the UI of the object it's databound to update it's items.
So what I'm trying to do, is download a file from my server, parse it with json, then update the ObservableCollection with the new data. However, the webclient doesn't seem to be downloading the new data until the app is re opened!
Here's a gif showing how the app works at the moment:
And here's my code (cut down a bit):
Dim aList As New ObservableCollection(Of classes.consoles)
Private Sub PhoneApplicationPage_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
checkforconsoles()
End Sub
Public Sub checkforconsoles()
Dim wc As New WebClient()
AddHandler wc.DownloadStringCompleted, AddressOf downloaded
wc.DownloadStringAsync(New Uri("http://localhost/api/?function=GetConsolesForUser&userid=" & id))
End Sub
Private Sub downloaded(sender As Object, e As DownloadStringCompletedEventArgs)
aList.Clear()
'MessageBox.Show(e.Result)
Dim o As JObject = JObject.Parse(e.Result)
Dim jarray As JArray = DirectCast(o("results"), JArray)
Try
Dim i As Integer = jarray.Count()
For i = 0 To jarray.Count() - 1 Step 1
Dim id As String = jarray(i)("id").ToString
Dim name As String = jarray(i)("name").ToString
Dim image As String = jarray(i)("image").ToString
MessageBox.Show(name)
Dim c As classes.consoles = New classes.consoles()
c.categoryimage = New Uri(image)
c.categoryname = name
c.categoryid = id
aList.Add(c)
Next
listBoxview.ItemsSource = aList
StackPanel1.Visibility = Windows.Visibility.Collapsed
StackPanel2.Visibility = Windows.Visibility.Visible
Catch ex As Exception
StackPanel2.Visibility = Windows.Visibility.Collapsed
StackPanel1.Visibility = Windows.Visibility.Visible
End Try
End Sub
Private Sub ApplicationBarIconButton_Click_1(sender As System.Object, e As System.EventArgs)
checkforconsoles()
End Sub
Does anybody have any clue what's wrong? :(
Thanks in advance.
It's a cachine issue with the WebClient. You can append a random query string to ensure that the URL is always unique so that the WebClient doesn't cache the results. One way to do this is to add a random GUID value since it's very unlikely to generate two of the same GUIDs in a short time frame.
wc.DownloadStringAsync(New Uri("http://localhost/api/?function=GetConsolesForUser&
userid=" & id & "&random=" + Guid.NewGuid().ToString()))