array of arrays visual basic - arrays

I'm developing a module for capture Attlogs from a ZKSoftware Fingerprint Biometric and send it to MySQL database using the SDK that came with the CD, so far I manage to connect successfully to the clock, display the logs on a listview, but I got stuck pushing the values on a multidimensional array, i'm sure it's a matter of declaration but I better ask for help... the code is as follows:
Dim thisLog(1) As String
Dim allLogs()() As String = New String()() {}
afterwards where the iteration (i) load the Attlogs in the listview I got:
thisLog = {sdwEnrollNumber, idwYear.ToString() & "-" + idwMonth.ToString() & "-" & idwDay.ToString() & " " & idwHour.ToString() & ":" & idwMinute.ToString() & ":" & idwSecond.ToString()}
allLogs(i) = {thisLog(0), thisLog(1)}
The error I'm getting is related to the size of the array, so the question can be resumed in how can I create a rectangular array (2)(n) with every row of the captured data. Thanks in advance

I would highly suggest you create a class to store the data in. Have a List(Of LogEntry) afterward. This would make your code a lot easier to read.
Class LogEntry
Public Property EnrollNumber As String
Public Property EntryDate As DateTime
Public Sub New(ByVal enrollNumber As String, ByVal entryDate As DateTime)
Me.EnrollNumber = enrollNumber
Me.EntryDate = entryDate
End Sub
End Class
For adding a new record, you just need to create an instance of that class and add it to the list.
Dim allLogs As New List(Of LogEntry)
allLogs.Add(New LogEntry(sdwEnrollNumber, New DateTime(idwYear, idwMonth, idwDay, idwHour, idwMinute, idwSecond)))
Since you'll now have a valid date instead of a concatenation of string, it'll be easy to do manipulation afterward.
Console.WriteLine(allLogs(0).EnrollNumber)
Console.WriteLine(allLogs(0).EntryDate.ToString("yyyy-MM-dd HH:mm:ss"))

how can I create a rectangular array (2)(n) with every row of the captured data?
Use a List:
Dim allLogs As New List(Of String())()
allLogs.Add(New String(1) {sdwEnrollNumber, _
String.Format("{0}-{1}-{2} {3}:{4}:{5}", _
idwYear, idwMonth, idwDay, idwHour, idwMinute, idwSecond)} )
I might also use the appropriate DateTime constructor and format string to format that 2nd part, depending on how you get those idw variables in the first place.

Related

Why is my vb code not updating the ms access database (only cached temporarly)

I am doing a small system using Ms. Access (the database has more than 10 tables ) connecting to visual studio. I made a public class for opening the connection to the database so I can use it in every form. Everything is working and I can get the data from the database But any inserting or deleting data in forms, the database in ms access not getting the update. I can see the new records in forms but nothing in the database.
Imports System.Data.OleDb
Public Class dbconnectClass1
'create db connection
Private DBcon As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=dental_clinic.accdb;")
'prepare db command
Private dbcmd As OleDbCommand
' db data
Public DBDA As OleDbDataAdapter
Public DBDT As DataTable
'query parameters
Public params As New List(Of OleDbParameter)
'query statics
Public recordcount As Integer
Public Exception As String
Public Sub ExecQuery(query As String)
'reset query status
recordcount = 0
Exception = ""
Try
'open connection
DBcon.Open()
'create db command
dbcmd = New OleDbCommand(query, DBcon)
'load params into dbcommand
params.ForEach(Sub(p) dbcmd.Parameters.Add(p))
'clear params list
params.Clear()
'excute command and fill dataset
DBDT = New DataTable
DBDA = New OleDbDataAdapter(dbcmd)
recordcount = DBDA.Fill(DBDT)
Catch ex As Exception
Exception = ex.Message
End Try
'close the database connection
If DBcon.State = ConnectionState.Open Then DBcon.Close()
End Sub
'include query and command parameters
Public Sub addparam(name As String, value As Object)
Dim newparam As New OleDbParameter(name, value)
params.Add(newparam)
End Sub
End Class
This my code inside the forms:
Public Class NewExpense
Private access As New dbconnectClass1
' a varuble having the appointment Id to connect between 2 forms
Private appointmentNo As Integer
Private Function NoError(Optional report As Boolean = False) As Boolean
If Not String.IsNullOrEmpty(access.Exception) Then
If report = True Then MsgBox(access.Exception)
Return False
Else
Return True
End If
End Function
Private Sub Savebuttum_Click(sender As Object, e As EventArgs) Handles
Savebuttum.Click
Dim oDate As DateTime = Convert.ToDateTime(DateTimePicker1.Value)
access.addparam("#expensenme", expensenmtXT.Text)
access.addparam("#expensedetail", ExpenseDetailTXT.Text)
access.addparam("#expenseamount", ExpenseAmountTXT.Text)
access.addparam("#expensedate", oDate)
access.addparam("#expensepaidTo", paidtoTXT.Text)
access.ExecQuery("INSERT INTO Expense (Expenses_name, expense_details,
expenses_amount, ExpenseDate_Paid, ExpensePaid_To) Values (#expensenme,
#expensedetail, #expenseamount, #expensedate, #expensepaidTo);")
'report on errors
If Not String.IsNullOrEmpty(access.Exception) Then
MsgBox(access.Exception) : Exit Sub
'success
access.DBDA.Update(access.DBDT)
MsgBox("Expense Has been Added Successfully")
End Sub
End Class
Hum, you have this:
params.ForEach(Sub(p) dbcmd.Parameters.Add(p))
Great, we add the parmaters - looks good to go!!!
then, next line CLEARS all the work above!!! (the parameters are removed!!!!)
'clear params list
params.Clear()
Next up? Many will build a connection object, then a reader, and then a adaptor. But you ONLY need a data adaptor if you going to update a data table. if you just going to execute a command, then you don't need the data table, and you don't need a adaptor FOR that table. Adaptor = ability to modify a existing datatable (or dataset).
You are MUCH better to use the command object.
Why?
Because the command object has a connection object (don't need a separate one)
Because the command object has a data reader for you (no need for a whole data adaptor to JUST fill a table. And remember, you don't need a whole data adaptor UNLESS you are going to send/update a data table back to the database.
And because the command object has the command text, then you don't even need a variable for that!!!
And because all objects are in "one object", then really all you need is something to handy get you the connection.
So, for your insert example, we really don't gain by having that object, do we?
Ok, so here is your insert code without using those extra objects:
so in the following, I declare ONE variable, - the sql command object.
And do the insert
And as FYI? Your save button is not a save - but a insert button - every time you hit it, you will insert a new row. Lets deal with that issue in a bit.
So, here is our code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Using cmdSQL As New OleDbCommand("INSERT INTO Expense
(Expenses_name, expense_details,expenses_amount, ExpenseDate_Paid, ExpensePaid_To)
Values (#expensenme,#expensedetail, #expenseamount, #expensedate, #expensepaidTo)",
New OleDbConnection(My.Settings.TESTOLEDB))
With cmdSQL.Parameters
.Add("#expensenme", OleDbType.WChar).Value = expensenmtXT.Text
.Add("#expensedetail", OleDbType.WChar).Value = ExpenseDetailTXT.Text
.Add("#expenseamount", OleDbType.Currency).Value = ExpenseAmountTXT.Text
.Add("#expensedate", OleDbType.DBDate).Value = DateTimePicker1.Value
.Add("#expensepaidTo", OleDbType.WChar).Value = paidtoTXT.Text
End With
cmdSQL.Connection.Open()
cmdSQL.ExecuteNonQuery()
End Using
So things in above:
We have strong data typing and converstion.
Because of this, note how I did NOT have to create a separate date/time variable here.
Note the SAME for "money" or so called currency conversion - again strong data type by using parameters this way.
And is this a date only, or a date+ time value? If it is date, then
.Add("#expensedate", OleDbType.DBDate).Value = DateTimePicker1.Value
If it was/is a date + time, then this:
.Add("#expensedate", OleDbType.DBTimeStamp).Value = DateTimePicker1.Value
So, notice how all your object stuff REALLY did not help one bit, and in fact you did not really save code, and above actually had LESS variables defined to do the whole job.
Now, back to the insert issue/problem. (you save is doing a insert). But what about editing existing records?
So, I would suggest you work out the problem this way:
You create/get/have/assume a data row for the form.
The form takes the data row, fills the controls. You edit, and when you hit save, the data row is sent back to the datbase. So, once this works, then to add? Well, the add code will CREATE a new data row, save to database and THEN you send that new data row to the above eixsting form that can edit a data row, and can save a data row. So the form now is able to deal with both issues (adding vs editing existing). If the user dont' want the row, then you offer a delete button.
And REALLY nice is a data row means you don't deal with SQL, and don't deal with parmaters!!
So the code (desing pattern) I use is thus this:
dim da as oledbDataAdaptor
dim myTable as DataTable = MyRstEdit("SELECT * from tblHotels WHERE ID = " & lngID,da)
dim MyDataRow as DataRow = myTable.Rows(0)
' code to fill controls
txtHotelName.Text = MyDataRow("HotelName")
txtCity.Text = MyDataRow("City")
' etc. etc. etc.
Now to save? Well I put the values back into that DataRow like this:
MyDataRow("HotelName") = txtHotelName.Text
MyDataRow("City") = txtCity.Text
MyDateRow("BookingDate") = txtTimePick1.Value
da.Update(MyTable)
Notice how I don't have parameters, and even strong data type checking occurs for say the above Date/Time booking date column.
And the above is nice, since I don't have to deal with ANY parmaters to udpate a row of data.
The MyRstEdit routine looks like this and returns byREf a "da" (data adaptor).
Public Function MyrstEdit(strSQL As String, Optional strCon As String = "", Optional ByRef oReader As SqlDataAdapter = Nothing) As DataTable
' Myrstc.Rows(0)
' this also allows one to pass custom connection string - if not passed, then default
' same as MyRst, but allows one to "edit" the reocrdset, and add to reocrdset and then commit the update.
If strCon = "" Then
strCon = GetConstr()
End If
Dim mycon As New SqlConnection(strCon)
oReader = New SqlDataAdapter(strSQL, mycon)
Dim rstData As New DataTable
Dim cmdBuilder = New SqlCommandBuilder(oReader)
Try
oReader.Fill(rstData)
oReader.AcceptChangesDuringUpdate = True
Catch
End Try
Return rstData
End Function
So, now in vb.net, I actually find it is LESS code then even writing + using recordsets in MS-Access VBA code.
However, BEFORE you go down ANY of the above road?
Have you considered using the vb.net data binding features. Data-binding in vb.net means that you do NOT write ANY of the above code. it means that vb.net will do all of the dirty work, and write and setup ALL OF the code for you to edit data on a form. The end result is you don't write any code to update a table.
You do have to use + create a "data set". Once done, then you just drag controls onto the form, and you even get this. So you just drop in a dataset, table adaptor, Binding navagator, and you get this:
Note now the tool bar at the top (and you can place it on teh bottom if you wish). So you get this:
So that WHOLE form was created without having to write ONE line of code. And you can see we have navigation, edits and saves and even the ability to add. So, you can build up a editing form - and it thus becomes similar to say working in MS-Access and ZERO lines of code is required to build the above form.
However, if you ARE going to roll your own code? Then use a data row. That way you can shuffle data to/from the table, and NOT have to use parmaters and SQL update and insert statements - but ONLY have nice clean code in which you shove, or get values from that data row. .net will "write" all the update stuff for you.

refresh textbox when powerpoint slide is shown

I'm using PowerPoint 2016 for a Wallboard display and I'd like it to pull a number from an MSSQL-Server table. I can get the SQL data into Powerpoint easily enough but I would like the data to refresh every day automatically and leave the wallboard running continuously.
I have a textbox on a slide that pulls data from an SQL VBA script. Is there a way to automatically run the script each time the slide is shown while the presentation is running or have the script run once every 24 hours to refresh the textbox?
This is a tricky and interesting problem and I'll admit that this is most of the solution, but there is a missing part. I haven't done much programming in Powerpoint, so it was a challenge. When you open the VBE, there are no modules, classes, or objects of any kind available. This is quite different from Word and Excel. This means we're all on our own...
I created a Presentation with five slides. On the third slide, I inserted some objects so it looked like this:
For the VBA part, the first thing I had to learn was to create a class module that will catch all of the events for the presentation. My very simple class is called EventClassModule and looks like this:
Option Explicit
Public WithEvents App As Application
Private Sub App_SlideShowNextSlide(ByVal Wn As SlideShowWindow)
If Wn.View.CurrentShowPosition = 3 Then
UpdateTheCount Wn.View.Slide
End If
End Sub
So now in a regular module, you have to run something to create and initialize this class as a global object.
Option Explicit
Dim eventClass As EventClassModule
Sub InitializeApp()
Set eventClass = New EventClassModule
Set eventClass.App = Application
End Sub
In my testing, I just manually ran the InitializeApp procedure to create the global object. This is the missing part of my solution... - I don't know how to automatically run this initialization to create the object. Maybe a ribbon button?
Then, also in the regular code module is the procedure to update the textbox:
Public Sub UpdateTheCount(ByRef thisSlide As Slide)
'--- loop through all the shapes to find the correct textbox,
' then update the value for display
Const LABEL_TEXT As String = "Value to update:"
Dim shp As Shape
For Each shp In thisSlide.Shapes
If shp.Type = msoTextBox Then
Dim theText As String
theText = shp.TextFrame.TextRange.Text
If InStr(1, theText, LABEL_TEXT, vbTextCompare) = 1 Then
Dim colonPos As Long
Dim theValue As Long
colonPos = InStr(1, theText, ":", vbTextCompare)
theValue = CLng(Right$(theText, Len(theText) - colonPos))
theValue = theValue + 1
theText = LABEL_TEXT & " " & theValue
shp.TextFrame.TextRange.Text = theText
End If
End If
Next shp
End Sub
Once your code is in place and you've run the InitializeApp() sub manually, just start the slide show (and probably set it to loop from the end) and step through it. The textbox value will update and increment automatically.
I'm interested in learning how to kick this off automatically from someone who's got that experience.

Using CSV .txt files with arrays in VB.NET to edit data?

I'm a beginner trying to learn VB.NET and I'm not quite sure how I'll explain this, but I'll give it a shot. Basically, I've written a txt file with about 10 lines of data in CSV form.
For example:
John, 10, 14
Michael, 14, 27
Billy, 13, 45
etc, etc....
I just want to be able to read and edit particular lines - not necessarily add new lines.
Just wondering if someone could just outline how I'd go about this - not asking anyone to write the program for me. I just don't know what to do and I couldn't understand other answers I've found on SO that attempted to solve the same problem. I don't know if I'm just a bit dense or something so it'd be great if someone could perhaps give a simple, 'dumbed-down' outline of what I need to do.
Thank you.
as stated in the comments you usually read all the file into memory, manipulate it and write it all back.
dotnet has a method that puts a file content in an array (line by line)
if you need to access individual cells in the CSV you probably want to run the split method on each line and join to merge them back together.
the split/join methods are either an method of the string/array object or its in the Strings namespace
a method for writing the file back is also in the System.IO Namespace
You don't asking to write the code for you, I can understand you but I think there is no way to show how can you do that. I used split/join methods as #weberik mentioned. It is a simple console application:
Public Class Sample
Public Shared Sub Main()
CreateExampleFileIfNotExists()
'lines variable is an "Array"
Dim lines() As String = IO.File.ReadAllLines("Example.txt")
'write items to the console
ShowItems(lines, "Values before edit:")
'edit the items
EditItems(lines)
'write edited items to the console
ShowItems(lines, "Values after edit:")
'save changes?
Save(lines)
'finish
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
Public Shared Sub ShowItems(lines() As String, header As String)
Console.WriteLine(header)
Dim headers() As String = {"Name:", "Value1:", "Value2:"}
WriteItems(headers)
For Each line In lines
WriteItems(line.Split(","))
Next
End Sub
Public Shared Sub EditItems(lines() As String)
For i As Integer = 0 To lines.Length - 1
Dim line As String = lines(i)
Dim values() As String = line.Split(",")
'edit the item
values(0) = "Edited " & values(0)
values(1) += i
values(2) *= i
lines(i) = String.Join(",", values)
Next
Console.WriteLine() 'empty line
End Sub
Public Shared Sub WriteItems(itemValues() As String)
Dim line As String = ""
For Each item In itemValues
line &= item & vbTab & vbTab
Next
Console.WriteLine(line)
End Sub
Public Shared Sub CreateExampleFileIfNotExists()
If Not IO.File.Exists("Example.txt") Then
IO.File.WriteAllLines("Example.txt", {"John,10,14", "Michael,14,27", "Billy,13,45"})
End If
End Sub
Public Shared Sub Save(lines() As String)
Console.WriteLine(vbCrLf & "Do you want to save the changes? Y/N")
Dim result = Console.ReadKey()
Console.WriteLine()
Select Case result.Key
Case ConsoleKey.Y
IO.File.WriteAllLines("Example.txt", lines)
Console.WriteLine("The changes has been saved.")
End Select
End Sub
End Class

How to have a global Dictionary in VB.NET/WPF application to save data from different windows?

I am new to VB.NET and WPF.
I am building a "Questionnaire" app. Users will be presented sequentially with different questions/tasks (windows). After they respond on each question/task and press a "submit" button a new window will open with a new question/task, and previous window will close. After each question, when the button is pressed, I need to store data to some global object. After all questions are answered the data of this object should be written out to the output file.
I figured out that Dictionary will be the best to store the results after each window.
I am not sure how, where to create this global Dictionary and how to access it. Should I use View Model? If yes, can you give an example? Or, should it be just a simple class with shared property? (something like this)
EDIT 2: I tried many different ways recommended online
GlobalModule:
Module GlobalModule
Public Foo As String
End Module
GlobalVariables:
Public Class GlobalVariables
Public Shared UserName As String = "Tim Johnson"
Public Shared UserAge As Integer = 39
End Class
Global properties:
Public Class Globals
Public Shared Property One As String
Get
Return TryCast(Application.Current.Properties("One"), String)
End Get
Set(ByVal value As String)
Application.Current.Properties("One") = value
End Set
End Property
Public Shared Property Two As Integer
Get
Return Convert.ToInt32(Application.Current.Properties("Two"))
End Get
Set(ByVal value As Integer)
Application.Current.Properties("Two") = value
End Set
End Property
End Class
Here is where I save the data to global variables/properties in the first window. I need to store data in this subroutine before closing an old window and opening a new window. I use MessageBox just for testing.
Private Sub btnEnter_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnEnter.Click
Dim instructionWindow As InstructionsWindow
instructionWindow = New InstructionsWindow()
Application.Current.Properties("number") = textBoxValue.Text
Globals.One = "2"
Globals.Two = 3
MessageBox.Show("GlobalVariables: UserName=" & GlobalVariables.UserName & " UserAge=" & GlobalVariables.UserAge)
GlobalVariables.UserName = "Viktor"
GlobalVariables.UserAge = 34
GlobalModule.Foo = "Test Foo"
'testing if it saved tha value
'MessageBox.Show(Application.Current.Properties("number"))
Application.Current.MainWindow.Close()
instructionWindow.ShowDialog()
End Sub
Next subroutine is where I am trying to retrieve the value from global Properties/variables in the second window, but message boxes come out empty. There might also the case that I am assigning values in a wrong way, or not reading them in a right way (casting?) :
Private Sub FlowDocReader_Initialized(ByVal sender As Object, ByVal e As System.EventArgs) Handles FlowDocReader.Initialized
' Get a reference to the Application base class instance.
Dim currentApplication As Application = Application.Current
MessageBox.Show(currentApplication.Properties("number"))
MessageBox.Show("One = " & Globals.One & " Two = " & Globals.Two)
MessageBox.Show("GlobalVariables: UserName=" & GlobalVariables.UserName & " UserAge=" & GlobalVariables.UserAge)
MessageBox.Show("GlobalModule.Foo = " & GlobalModule.Foo)
Dim filename As String = My.Computer.FileSystem.CurrentDirectory & "\instructions.txt"
Dim paragraph As Paragraph = New Paragraph()
paragraph.Inlines.Add(System.IO.File.ReadAllText(filename))
Dim document As FlowDocument = New FlowDocument(paragraph)
FlowDocReader.Document = document
End Sub
Thanks.
You can make public Dictionary property for form and put your dictionry to this property or make constructor with Dictionary argument.
You already have this dictionary Application.Properties
Look here, please.
First, you can define a dictionary (list of lists) as follows at the beginning of a form or in a module
Dim dic As New Dictionary(Of String, List(Of String))
As the user completes questions on a form, write the partucular form number and query results to a single record in the dic before going to the next form (place this code into the "Next" button):
'Assume q1response=3, q2response=4,..., qpresponse="text", etc.
Dim myValues As New List(Of String)
myValues.Add(formname)
myValues.Add(q1response)
myValues.Add(q2response)
.
.
myValues.Add(qpresponse)
dic.Add(username, myValues)
When a user is done, there will be multiple records in the dictionary, each of which starts with their name and is followed by question responses. You can loop through multiple dictionary records, where each record is for a user using the following:
For Each DictionaryEntry In dic 'this loops through dic entries
Dim str As List(Of String) = DictionaryEntry.Value
'here you can do whatever you want with results while you read through dic records
'username will be = str(0)
'formname will be str(1)
'q1 response on "formname" will be str(2)
'q2 response on "formname" will be str(3)
'q3 response on "formname" will be str(4)
...
Next
The trick is that there will be multiple dictionary records with results for one user, where record one can have results like "John Doe,page1,q1,q2,q3" and record 2 will be "John Doe,page2,q4,q5,q6." Specifically, the "str" in the above loop will be an array of string data containing all the items within each dictionary record, that is, in str(0), str(1), str(2),... This is the information you need to work with or move, save, analyze, etc.
You can always put all the code I provided in a class (which will be independent of any form) and dimension the sic is a Sub New in this class, with the updating .Add values lines in their own sub in this same class). Then just Dim Updater As New MyNewClassName. Call the Updater in each continue button using Call Updater.SubNameWithAddValues(q1,q2,...qp). It won't matter where you are in your program since you using a specific class. The one thing I noticed with my code is that you can only use the line that adds the "key" or the username once, so use it after the last query -so put it in a Sub Finished in your new class and call as Call Updater.Finished(username,q30,q31,last)

Convert list (of string) from datareader to string

I've captured some data from a datareader into a list and now I'm wondering what's the best way to put these out into strings.
The requirement I have is I need to grab field names from a table and then out put these as headings on a page.
objConn = New SqlConnection(strConnection)
objConn.Open()
objCmd = New SqlCommand(strSQL, objConn)
rsData = objCmd.ExecuteReader(0)
If rsData.HasRows Then
Do While (rsData.Read())
Dim SubjectNames As New List(Of String)
SubjectNames.Add(rsData.GetString("subject"))
Loop
SubjectList = SubjectNames.ToArray
Now I was thinking ToArray and was wondering how then to output all of the list entries into strings that I can then use later on.
It's also prudent to note that I'm doing this all inline as the CMS I have to use doesn't allow any code behind.
If i understand you correctly you don't know how to convert a List(Of String) to a string. You can use String.Join and specify which string you want to use to join the words:
Dim SubjectNames As New List(Of String)
Do While (rsData.Read())
SubjectNames.Add(rsData.GetString("subject"))
Loop
Dim headers As String = String.Join(", ", SubjectNames)
Note that i've moved the declaration of the list outside of the loop because otherwise you would always create a new list for every record.
Edit: So you don't know how to access elements in a List or Array.
Elements in a List(Of String) or String() are already individual strings. You access each element via indexer. For example: Dim firstSubject = SubjectNames(0) or via Linq: firstSubject = SubjectNames.First(). For the 10th element: Dim subject10 = SubjectNames(9) since indexes are zero based.
MSDN: Arrays in Visual Basic

Resources