Good evening,
Following is the code I used for reading the files and folders from a drive etc.
Public Class LoadingBox
Public counter As ULong
Public OpenRecords As New Dictionary(Of String, MainWindow.records)
Public Path As String
Public Diskname As String
Private WithEvents BKWorker As New BackgroundWorker()
Public Sub New(ByVal _Path As String, ByVal _Diskname As String)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Path = _path
Diskname = _diskname
End Sub
Private Sub GetStructure(ByVal tempdir As String, ByVal ParentID As String, ByVal DiskName As String)
Dim maindir As DirectoryInfo = My.Computer.FileSystem.GetDirectoryInfo(tempdir)
For Each Dir As DirectoryInfo In maindir.GetDirectories
Try
Dim d As New MainWindow.records
d.Filename = Dir.Name
d.Folder = True
d.Rowid = Date.UtcNow.ToString() + counter.ToString()
d.Size = 0
d.ParentID = ParentID
d.DiskName = DiskName
d.DateCreated = Dir.CreationTimeUtc
d.DateModified = Dir.LastWriteTimeUtc
OpenRecords.Add(d.Rowid, d)
'Label1.Content = "Processing: " + Dir.FullName
BKWorker.ReportProgress(0, Dir.FullName)
counter = counter + 1
GetStructure(Dir.FullName, d.Rowid, DiskName)
Catch ex As Exception
End Try
Next
For Each fil As FileInfo In maindir.GetFiles
Try
Dim d As New MainWindow.records
d.Filename = fil.Name
d.Folder = False
d.Rowid = Date.UtcNow.ToString() + counter.ToString()
d.Size = fil.Length
d.ParentID = ParentID
d.DiskName = DiskName
d.DateCreated = fil.CreationTimeUtc
d.DateModified = fil.LastWriteTimeUtc
OpenRecords.Add(d.Rowid, d)
'Label1.Content = "Processing: " + fil.FullName
BKWorker.ReportProgress(0, fil.FullName)
counter = counter + 1
Catch ex As Exception
End Try
Next
End Sub
Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
counter = 0
BKWorker.WorkerReportsProgress = True
AddHandler BKWorker.DoWork, AddressOf BKWorker_Do
AddHandler BKWorker.ProgressChanged, AddressOf BKWorker_Progress
AddHandler BKWorker.RunWorkerCompleted, AddressOf BKWorker_Completed
BKWorker.RunWorkerAsync()
'GetStructure(Path, "0", Diskname)
End Sub
Private Sub BKWorker_Do(ByVal sender As Object, ByVal e As DoWorkEventArgs)
'Throw New NotImplementedException
GetStructure(Path, "0", Diskname)
End Sub
Private Sub BKWorker_Progress(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
'Throw New NotImplementedException
Label1.Content = "Processing: " + e.UserState.ToString()
If ProgressBar1.Value = 100 Then
ProgressBar1.Value = 0
End If
ProgressBar1.Value = ProgressBar1.Value + 1
End Sub
Private Sub BKWorker_Completed(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
'Throw New NotImplementedException
MessageBox.Show("Completed")
Me.Close()
End Sub
End Class
However the problem is that, the background thread is able to read files very fast, but the UI thread is not able to keep up the speed with it, could you please advice me on how I can solve this issue.
You almost never want to report progress on every single item when you're iterating through that many items.
I would suggest finding some reasonable number of files to wait for before reporting progress. Every 5th or every 10th or so on. You probably want to take a look at what your normal number of files is. In other words, if you're normally processing only 25 files, you probably don't want to only update every 10 files. But if you're normally processing 25000 files, you could maybe even only update every 100 files.
One quick answer would be to only report the progress when a certain amount of time has passed that way if 10 files were processed in that time the UI isn't trying to update one each one. If things are processing that fast then you really don't need to update the user on every single file.
Also on a quick side note if your ProgressBar isn't actually reporting progress from 0 to 100% you might want to just set its IsIndeterminate property to true instead of increasing the percent and then resetting it back to 0.
Related
I have a VB.Net program that loops through array's to try to figure out where bottles are on a "conveyor". The point of this program is to visually show staff, how the conveyor works using VB.net and Labels. It's extremely difficult to explain, so I’ll do my best.
Bottle_Number(10) Bottle_Position(128)
There are 10 bottles that I want to track at all 128 stops on the conveyor.
We have a conveyor that can only fit 10 bottles. I need to track the position of each of the 10 bottles. Once bottle 11 comes on - That means bottle 1 is completed and off the conveyor. So, bottle 11 becomes bottle 1, so I need to reset the position of bottle1 to 0, and continue tracking bottles 2-9 while also tracking bottle 11(Not bottle 1). Once bottle 12 comes on it becomes bottle 2, and I need to reset the position of bottle 2 to '0' and continue tracking all bottles.
Any help would be appreciated.
Here is my code:
Public Class frmMain
Dim Product_Position(10) As Integer
Dim Inches_Per_Pulse As Integer
Dim PulseNumber As Integer
Dim Product_Counter As Integer
Dim Product_Location(10) As Integer
Dim Function1 As Integer
Dim Function2 As Integer
Dim Function3 As Integer
Dim Function4 As Integer
Dim Function5 As Integer
Dim Function6 As Integer
Dim Function7 As Integer
Dim Function8 As Integer
Dim Function9 As Integer
Dim Function10 As Integer
Dim Product_in_Tunel As Integer
Dim test As Integer
Dim Roll_OVer As Boolean
Dim Product_Counter_Test As Integer
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
lblStatus.BackColor = Color.Green
lblStatus.Text = "Conveyor Status: Running"
End Sub
Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click
lblStatus.BackColor = Color.Red
lblStatus.Text = "Conveyor Status: Off"
End Sub
Private replace_next As Integer
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
If Product_Counter = 10 Then
replace_next += 1
If replace_next > 10 Then
replace_next = 1 ' replace them in turn 1..10, then loop back to 1
Product_Position(replace_next) = 0 ' put initial position here
End If
End If
Product_Counter = Product_Counter + 1
If Product_Counter > 10 Then
Product_Counter = 1
Roll_over = True
End If
'MsgBox(Product_Counter)
'MsgBox(replace_next)
End Sub
Private Sub btnPulse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPulse.Click
Get_Location()
End Sub
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
PulseNumber = "0"
Inches_Per_Pulse = "1"
Roll_OVer = False
'MsgBox("Test")
End Sub
Public Sub Get_Location()
'MsgBox(Product_Counter)
If Roll_OVer = True Then
Product_Counter_Test = 10
'MsgBox("i'm stuck here")
End If
If Roll_OVer = False Then
Product_Counter_Test = Product_Counter
End If
'MsgBox(Product_Counter_Test)
'MsgBox("am I here - Yes")
For test = 1 To Product_Counter_Test
'MsgBox("This works")
Product_Position(test) = Product_Position(test) + Inches_Per_Pulse
Next
PulseNumber = PulseNumber + 1
ClearLabels()
lblProduct1Position.Text = Product_Position(1)
lblProduct2Position.Text = Product_Position(2)
lblProduct3Position.Text = Product_Position(3)
lblProduct4Position.Text = Product_Position(4)
lblProduct5Position.Text = Product_Position(5)
lblProduct6Position.Text = Product_Position(6)
lblProduct7Position.Text = Product_Position(7)
lblProduct8Position.Text = Product_Position(8)
lblProduct9Position.Text = Product_Position(9)
lblProduct10Position.Text = Product_Position(10)
End Sub
Public Sub ClearLabels()
lblProduct1Position.Text = ""
lblProduct2Position.Text = ""
lblProduct3Position.Text = ""
lblProduct4Position.Text = ""
lblProduct5Position.Text = ""
lblProduct6Position.Text = ""
lblProduct7Position.Text = ""
lblProduct8Position.Text = ""
lblProduct9Position.Text = ""
lblProduct10Position.Text = ""
End Sub
The Pulse button is what is actually driving the conveyor, each pulse (click of the button) means the conveyor is moving forward.
Right now once the program gets to bottle 11, it resets and only moves forward the "new" bottle (bottle1). It should continue incrementing the remaining bottles until they reach the end and do the same for them - Reset the position to 0 and begin counting again.
As far as I understand it, once you have 11 bottles, you don't want to reset to only one bottle, but instead still have 10 bottles, and replace one of them. You'll need a second variable to keep track of which is to be replaced.
So instead of :
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
Product_Counter = Product_Counter + 1
If Product_Counter > 10 Then Product_Counter = 1
End Sub
It would be something like:
Private Replace_Next as Integer = 0
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
If Product_Counter = 10 Then
Replace_Next += 1
If Replace_Next > 10 Then Replace_Next = 1 ' replace them in turn 1..10, then loop back to 1
Product_Position(Replace_Next) = .... ' put initial position here
Else
Product_Counter = Product_Counter + 1
End If
End Sub
Your conveyor is FIFO (first-in, first-out), so rather than constantly shifting, reindexing and/or rebuilding (=reset?) an array to make it seem like it is FIFO, Net includes the Queue(Of T) collection which is FIFO.
A LinkedList(Of T) could also be used. A plain List(Of T) would also work, but if the add/remove frequency is high, that will result in the same inefficient shifting taking place under the hood that you have with an array.
The only issue is enforcement of the size limit, which is easily handled with a small class wrapper. I assume there is something interesting or identifiable about the bottles other than their position. The test code uses a sequence ID and the contents.
Friend Class Bottle
Public Property Contents As String
Public Property SequenceID As Int32
' etc
Public Overrides Function ToString() As String
Return String.Format("{0}: ({1})", SequenceID.ToString("00"), Contents)
End Function
End Class
You likely have more relevant information to show. The, the collection class:
Friend Class BottleQueue
Private mcol As Queue(Of Bottle)
Private lbls As Label()
Private MaxSize As Int32 = 10 ' default
Public Sub New(size As Int32)
MaxSize = size
mcol = New Queue(Of Bottle)
End Sub
Public Sub New(size As Int32, l As Label())
Me.New(size)
lbls = l
End Sub
Public Sub Add(b As Bottle)
mcol.Enqueue(b)
Do Until mcol.Count <= MaxSize
mcol.Dequeue()
Loop
UpdateDisplay()
End Sub
Public Function Peek() As Bottle
Return mcol.ElementAtOrDefault(0)
End Function
Public ReadOnly Property Count() As Int32
Get
Return mcol.Count
End Get
End Property
Public Function Remove() As Bottle
Dim b As Bottle = Nothing
If mcol.Count > 0 Then
b = mcol.Dequeue
UpdateDisplay()
End If
Return b
End Function
Private Sub UpdateDisplay()
Dim n As Int32
If lbls Is Nothing OrElse lbls.Count = 0 Then
Return
End If
For n = 0 To mcol.Count - 1
lbls(n).Text = mcol.ElementAtOrDefault(n).ToString
Next
For n = n To lbls.Count - 1
lbls(n).Text = "(empty)"
Next
End Sub
Public ReadOnly Property GetQueue As Bottle()
Get
Return mcol.ToArray()
End Get
End Property
End Class
The class has 2 display means built in. One updates a set of labels. Since it is a collection, it also provides a way to get the current collection in order for a collection type control such as a Listbox. An even better way would be if the collection itself was "observable", so it could be used as a datasource.
It also provides a way to Removethe next bottle manually. Removing from a specific index (e.g. Remove(3)) is antithetical to a Queue, so it isnt implemented.
test code:
' form level vars:
Private BottleQ As BottleQueue
Private BottleID As Int32 = 7
' form load, passing the labels to use
' using a queue size of FIVE for test
BottleQ = New BottleQueue(5, New Label() {Label1, Label2, Label3, Label4, Label5})
Adding an item:
Dim material = {"Napalm", "Beer", "Perfume", "Pepsi", "Cyanide", "Wine"}
' add new bottle with something in it
BottleQ.Add(New Bottle With {.Contents = material(RNG.Next(0, material.Count)),
.SequenceID = BottleID})
BottleID += 1
' clear and show the contents in a listbox:
lbQueView.Items.Clear()
lbQueView.Items.AddRange(BottleQ.GetQueue)
The BottleId arbitrarily starts at 7, the contents are random. BTW, material shows just about the only way I ever use an array: when the contents are fixed and known ahead of time. In almost all other cases, a NET collection of one sort or another, is probably a better choice.
Because it is not an observable collection (and that is a little at odds with the FIFO nature), the listbox needs to be cleared each time. That could be internal to the class like the label display is. Results:
On the right, the first 5 are shown in order; 3 clicks later, the result is on the left: everything moved up 3 and 3 new items have been added.
Note: If the code using this needs to know when/which Bottle is removed from the conveyor, the class could include a ItemRemoved event which provides the item/Bottle just removed when adding forces one out. That is probably the case, but the question doesnt mention it.
Hello this is my first time posting here. well to the point, I have pieced together
a app that is able to load a text file, add on the fly to a "listbox", now all i need it to Ping all ips in said "listbox" but i get an error and stops working. need help to ping all ips.
Private Sub Go_Click(sender As Object, e As EventArgs) Handles Go.Click
If ListBox1.Items.Count <= 0 Then
MsgBox("Please Add at Least One IP or Website!")
Exit Sub
End If
For l_index As Integer = 0 To ListBox1.Items.Count - 1 'THIS IS WHERE CODE STOPS WORKING, NEED "MAGIC CODE" HERE
Dim lines As String = CStr(ListBox1.Items(l_index))
BackgroundWorker1.RunWorkerAsync(lines)
Next
End Sub
I am using Openfiledialog to load Text File to listbox1 and backgroundworker to do the ping. I am using
Imports System.Net
Imports System.Net.NetworkInformation
Imports System.Threading
Imports System.IO
What i want to do is once that all "IPs" are in the listbox i want to press Go to Ping all Ips. How can i get this to work?
Imports System.Net
Imports System.Net.NetworkInformation
Imports System.Threading
Imports System.IO
Public Class Main
Private Sub AboutUpingToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles AboutUpingToolStripMenuItem.Click
AboutUping.Show()
End Sub
Private Sub MenuStrip1_ItemClicked(sender As Object, e As ToolStripItemClickedEventArgs) Handles MainMenu.ItemClicked
End Sub
Private Sub QuitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles QuitToolStripMenuItem.Click
Application.Exit()
End Sub
Private Sub OpenFileDialog1_FileOk(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles OpenFileDialog1.FileOk
Dim lines = File.ReadAllLines(OpenFileDialog1.FileName)
ListBox1.Items.AddRange(lines)
End Sub
Private Sub OpenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OpenToolStripMenuItem.Click
OpenFileDialog1.ShowDialog()
End Sub
Private Sub NewToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles NewToolStripMenuItem.Click
Create.Show()
End Sub
Private Sub ToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles ToolStripMenuItem1.Click
End Sub
Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Go_Click(sender As Object, e As EventArgs) Handles Go.Click
If ListBox1.Items.Count <= 0 Then
MsgBox("Please Add at Least One IP or Website!")
Exit Sub
End If
For l_index As Integer = 0 To ListBox1.Items.Count - 1 'THIS IS WHERE CODE STOPS WORKING, NEED "MAGIC CODE" HERE
Dim lines As String = CStr(ListBox1.Items(l_index))
BackgroundWorker1.RunWorkerAsync(lines)
Next
End Sub
Private Sub CloseFileToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles CloseFileToolStripMenuItem.Click
TextBox1.Clear()
ListBox1.Items.Clear()
End Sub
Private Sub cmdADD_Click(sender As Object, e As EventArgs) Handles cmdADD.Click
Dim myitem
myitem = txtADD.Text()
ListBox1.Items.Add(myitem)
txtADD.Clear()
End Sub
Private Sub cmdRemove_Click(sender As Object, e As EventArgs) Handles cmdRemove.Click
For a As Int32 = ListBox1.SelectedItems.Count - 1 To 0 Step -1
For i As Int32 = ListBox1.Items.Count - 1 To 0 Step -1
'-- compare the value of the select item to any given item in the list.
If ListBox1.SelectedItems(a) = ListBox1.Items(i) Then
'-- remove the item by the index we found
ListBox1.Items.RemoveAt(i)
'-- exit the inner for loop
Exit For
End If
Next
Next
End Sub
Private Sub cmdClear_Click(sender As Object, e As EventArgs) Handles cmdClear.Click
ListBox1.Items.Clear()
End Sub
Private Sub HelpToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles HelpToolStripMenuItem.Click
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim lines = DirectCast(e.Argument, String())
Dim Ping As New Ping
Dim replies As New List(Of PingReply)
For Each ip In lines
Dim reply = Ping.Send(ip)
replies.Add(reply)
Next
e.Result = replies
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
Dim sb As New System.Text.StringBuilder
Dim replies = DirectCast(e.Result, List(Of PingReply))
For Each reply In replies
Dim index As Integer
index += 1
sb.Append("Ping ").Append(index).Append(": ").Append(reply.Address).Append(" ").Append(reply.RoundtripTime).Append(" ms")
sb.AppendLine()
Next
TextBox1.Text = sb.ToString
End Sub
End Class
Your error is here
one of your ping fails and results an exception which is returned to the completed event handler and when the handler tries to get the result the TargetInvocationException exception is thrown
solution is to check the error
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Error Is Nothing Then
Dim sb As New System.Text.StringBuilder
Dim replies = DirectCast(e.Result, List(Of PingReply))
For Each reply In replies
Dim index As Integer
index += 1
sb.Append("Ping ").Append(index).Append(": ").Append(reply.Address).Append(" ").Append(reply.RoundtripTime).Append(" ms")
sb.AppendLine()
Next
TextBox1.Text = sb.ToString
Else
'error handling
End If
End Sub
additionally you may need to handle the actual error to protect rest of the ping replies otherwise because of 1 failure whole batch of result will be lost
For Each ip As String In lines
Try
Dim reply As PingReply = Ping.Send(ip)
replies.Add(reply)
Catch ex as PingException
'error handling
End Try
Next
Update
another point of error,
For l_index As Integer = 0 To ListBox1.Items.Count - 1
Dim lines As String = CStr(ListBox1.Items(l_index))
BackgroundWorker1.RunWorkerAsync(lines)
Next
since you are passing as single string from the method above and in the method below you are attempting to cast as string array so it fails, change it like this
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim ip = DirectCast(e.Argument, String)
Dim Ping As New Ping
Dim replies As New List(Of PingReply)
Try
Dim reply As PingReply = Ping.Send(ip)
replies.Add(reply)
Catch ex as PingException
'error handling
End Try
e.Result = replies
End Sub
also advised to use Option Strict On to reduce some type checking errors
Thanks!Got it to work! Sending "Listbox1" to array
Private Sub Go_Click(sender As Object, e As EventArgs) Handles Go.Click
Dim lines() As String = ListBox1.Items.OfType(Of String)().ToArray()
BackgroundWorker1.RunWorkerAsync(lines)
End Sub
Now it works app does not crash.
I have create multiple choice system where the user need to choose answer from 4 radiobutton before navigate to next question by clicking next button.
So, the I have problem in storing the selected radiobutton into database. At first I create a table where I create columns to store each answer but it failed. Now, I'm stuck. Please give any suggestion where i can store the answer.
Here I provide the code to load the question
p/s: I know i should ask this on different thread but I also stuck on how to randomize the radiobutton.
Public Property Counter() As Integer
Get
Return IIf(ViewState("counter") Is Nothing, 1, CInt(ViewState("counter")))
End Get
Set(ByVal value As Integer
ViewState("counter") = value
End Set
End Property
Protected Sub Next_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Counter += 1
question()
clean()
End Sub
Sub question()
conn.Open()
Dim cmd As New SqlCommand("Select * From ques Where Id=#Id", conn)
cmd.Parameters.AddWithValue("#Id", Counter)
Dim dr1 As SqlDataReader
dr1 = cmd.ExecuteReader
If dr1.Read() Then
Me.lblquestion.Text = dr1("question")
Me.RadioButton1.Text = dr1("right")
Me.RadioButton2.Text = dr1("wrong")
Me.RadioButton3.Text = dr1("wrong2")
Me.RadioButton4.Text = dr1("wrong3")
Else
conn.Close()
Counter += 1
question()
End If
conn.Close()
End Sub
Sub clean()
RadioButton1.Checked = False
RadioButton2.Checked = False
RadioButton3.Checked = False
RadioButton4.Checked = False
Next.Enabled = False
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
question()
End Sub
Protected Sub RadioButton1_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RadioButton1.CheckedChanged
Next.Enabled = True
End Sub
Protected Sub RadioButton2_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RadioButton2.CheckedChanged
Next.Enabled = True
End Sub
Protected Sub RadioButton3_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RadioButton3.CheckedChanged
Next.Enabled = True
End Sub
Protected Sub RadioButton4_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RadioButton4.CheckedChanged
Next.Enabled = True
End Sub
End Class
I would have a database structure like this:
TblQuizes
Quiz_Id int
Quiz_Name nvarchar(200) -- or any other number that meets your demands
TblQuestions
Question_Id int
Question_Quiz_Id int --(FK To TblQuizes)
Question_Text nvarchar(200) -- or any other number that meets your demands
TblAnswers
Answer_Id int
Answer_Question_Id int --(FK To TblQuestions)
Answer_Text nvarchar(200) -- or any other number that meets your demands
Answer_IsCorrect bit
TblResults
Result_Id int
Result_Quiz_Id int -- (FK to TblQuizes) (not even needed, just to convenience)
-- Add user data in this table if you need it
TblResultDetails
ResultDetails_Id int
ResultDetails_Result_Id int --(FK to TblResults)
ResultDetails_Answer_Id int (FK to TblAnswers)
Now what I would do is create a new record in TblResults for every user that answers the quiz, and store the users answers in TblResultDetails.
On this basic structure you can create views to give you the entire data you need to show the quiz to the user, or to show him how well he answered your questions, and so on. you can also see very easily if a user did not complete the quiz, just by comparing the number of records in TblQuetions and TblResultDetails for a specific quiz id.
Also, if you ever want to have questions with only 2 answer, or 6 answers, you don't have to change anything in the database structure or in your code to have that.
I have to code a WPF application for college which reads from a csv file. I get a null reference exception when I want to output the parts of the CSV lines into arrays. You can find the line where the error happens in commentary. Here is the code.
Imports System.Windows.Forms
Imports System.IO
Imports System.Globalization
Class MainWindow
Private foldername As String
Private arrGemeenten As String()
Private arrOppervlakte As Double()
Private arrInwoners As Integer()
Private arrDeelgemeenten As Integer()
Private Sub cboProvincie_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles cboProvincie.SelectionChanged
CSVInlezen()
End Sub
Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
FileBrowserAanmaken()
comboBoxVullen()
End Sub
Private Sub comboBoxVullen()
For Each file As String In IO.Directory.GetFiles(foldername)
If file.EndsWith(".csv") Then
Dim filenaam As String = System.IO.Path.GetFileNameWithoutExtension(file)
cboProvincie.Items.Add(filenaam)
End If
Next
End Sub
Private Sub FileBrowserAanmaken()
'folderbrowserdialog aanmaken
Dim fbd As New FolderBrowserDialog
fbd.SelectedPath = AppDomain.CurrentDomain.BaseDirectory
' Show the FolderBrowserDialog.
Dim result As DialogResult = fbd.ShowDialog()
If (result = Forms.DialogResult.OK) Then
foldername = fbd.SelectedPath
End If
End Sub
Private Sub CSVInlezen()
Dim filepath As String = foldername & "\" & cboProvincie.SelectedValue & ".csv"
If File.Exists(filepath) Then
fileInlezenHulpMethode(filepath)
End If
End Sub
Private Sub fileInlezenHulpMethode(ByVal path As String)
'declarations
Dim sr As New StreamReader(path)
Dim iTeller As Integer = 0
Dim arrLijn As String()
Dim culture As New System.Globalization.CultureInfo("nl-BE")
'eerste lijn meteen uitlezen, dit zijn kolomkoppen en hebben we niet nodig
'read out first line, these are titles and we don't need them
sr.ReadLine()
Do While sr.Peek <> -1
Dim lijn As String = sr.ReadLine()
arrLijn = lijn.Split(";")
arrGemeenten(iTeller) = Convert.ToString(arrLijn(0)) 'HERE I GET THE ERROR!
arrOppervlakte(iTeller) = Double.Parse(arrLijn(2), NumberStyles.AllowDecimalPoint, culture.NumberFormat)
arrInwoners(iTeller) = Integer.Parse(arrLijn(3), NumberStyles.Integer Or NumberStyles.AllowThousands, culture.NumberFormat)
arrDeelgemeenten(iTeller) = Convert.ToString(arrLijn(4))
Loop
End Sub
End Class
You haven't created the array, you have only created a reference for it. To create the array you need to specify a size, for example:
Private arrGemeenten As String(100)
However, to specify the size, you need to know the size when you create the array. (Well, actually you put all data in the first item, so just the size 1 would keep it from crashing, but I don't thing that's what you intended.) You probably want to use lists instead:
Private gemeenten As New List(Of String)()
Then you use the Add method to add items to the list:
gemeenten.Add(Convert.ToString(arrLijn(0)))
Also, consider putting the data in a single list of a custom object, instead of having several lists of loosely coupled data.
What's wrong in my code? It's not updating the TextBox and the ProgressBar while deleting files.
Imports System.Windows.Threading
Imports System.IO
Class MainWindow
Private Sub bt_Click(ByVal sender As Object,
ByVal e As RoutedEventArgs) Handles bt.Click
Dim sb As New System.Text.StringBuilder
Dim files = IO.Directory.EnumerateFiles(
My.Computer.FileSystem.SpecialDirectories.Temp, "*.*",
SearchOption.TopDirectoryOnly)
Dim count = files.Count
pb.Minimum = 0
pb.Maximum = count
For i = 0 To count - 1
Dim f = files(i)
Dispatcher.BeginInvoke(
New Action(Of String, Integer)(
Sub(str, int)
tb.SetValue(TextBox.TextProperty, str)
pb.SetValue(ProgressBar.ValueProperty, int)
End Sub),
DispatcherPriority.Send,
f, i + 1)
Try
File.Delete(f)
Catch ex As Exception
sb.AppendLine(f)
End Try
Dim exceptions = sb.ToString
Stop
Next
End Sub
End Class
I got this working with the BackgroundWorker object. This places your work in a background thread, with calls to update the UI going through the ProgressChanged event. I also used Invoke instead of BeginInvoke within the work loop, which forces the loop to wait for the UI to become updated before it proceeds.
Imports System.ComponentModel
Imports System.IO
Class MainWindow
Private WithEvents bw As New BackgroundWorker
Private Sub Button1_Click(ByVal sender As System.Object,
ByVal e As RoutedEventArgs) Handles btn.Click
pb.Minimum = 0
pb.Maximum = 100
bw.WorkerReportsProgress = True
bw.RunWorkerAsync()
End Sub
Private Sub bw_DoWork(ByVal sender As Object,
ByVal e As DoWorkEventArgs) Handles bw.DoWork
Dim sb As New System.Text.StringBuilder
Dim files = IO.Directory.EnumerateFiles(
My.Computer.FileSystem.SpecialDirectories.Temp, "*.*",
SearchOption.TopDirectoryOnly)
Dim count = files.Count
Me.Dispatcher.BeginInvoke(Sub()
tb.Text = "SOMETHING ELSE"
End Sub)
For i = 0 To count - 1
Dim f = files(i)
Dim myI = i + 1
Me.Dispatcher.Invoke(
Sub()
bw.ReportProgress(CInt((myI / count) * 100), f)
End Sub)
'Try
' File.Delete(f)
'Catch ex As Exception
' sb.AppendLine(f)
'End Try
Dim exceptions = sb.ToString
'Stop
Next
End Sub
Private Sub bw_ProgressChanged(
ByVal sender As Object,
ByVal e As ProgressChangedEventArgs) Handles bw.ProgressChanged
Dim fString As String = TryCast(e.UserState, String)
Me.Dispatcher.BeginInvoke(Sub()
tb.Text = fString
End Sub)
End Sub
End Class