Please help me with this!
I have a ListView with checkboxes enabled. I need to disable all the checked items checkboxes, where the user should not try to click it again.
Here is my code, where I am getting error.
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
Try
' submit
Dim path As String = "C:\Users\jtb43661\Documents\Visual Studio 2017\Projects\IGI Event Tracker\IGI Event Tracker\bin\Debug\Logs\Event.LOG"
If Not File.Exists(path) Then
Using sw As StreamWriter = File.CreateText(path)
End Using
End If
Using sw As StreamWriter = File.AppendText(path)
For Each item In ListView1.CheckedItems
sw.WriteLine(item.Text & "->" & " Completed-#---> " & Label2.Text)
item.SubItems.Add("Completed")
item.BackColor = Color.GreenYellow
'If item.subItems.text = "Completed" Then
'here I need to disable or lock the checked checkboxes
'End If
Next
sw.Close()
End Using
MsgBox("Events Submitted Successfully")
Catch ex As Exception
MsgBox(ex.Message.ToString)
Finally
End Try
End Sub
If I understand your implied logic correctly, once a ListviewItem is checked and contains a ListViewSubItem with the Text property equal to "Completed" you do not want the user to be able to uncheck that item. The addition of the "Completed" subitem is performed in a Button click event handler something like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For Each itm As ListViewItem In ListView1.CheckedItems
' add "Completed" subitem only if it does not currently exist
Dim hasCompleted As Boolean = False
For Each subitem As ListViewItem.ListViewSubItem In itm.SubItems
hasCompleted = subitem.Text.Equals("Completed")
If hasCompleted Then Exit For
Next
If Not hasCompleted Then itm.SubItems.Add("Completed")
Next
End Sub
As far as I know, there is no way to directly disable a ListViewItem to prevent it from being unchecked. However, the ListView does have the ItemCheck event that can be used to prevent changing the "Checked" state. The following code prevents the Checked state change if the item being "UnChecked" has a SubItem with the Text "Completed".
Private Sub ListView1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles ListView1.ItemCheck
If e.CurrentValue = CheckState.Checked Then
Dim item As ListViewItem = ListView1.Items(e.Index)
For Each subitem As ListViewItem.ListViewSubItem In item.SubItems
If subitem.Text.Equals("Completed") Then
e.NewValue = e.CurrentValue ' do not allow the change
Exit For
End If
Next
End If
End Sub
Related
I'm trying to load a new webpage through the control webview2 in .net6+ windows forms, and I'm using a listbox to extract any single item and add it to the url to load on webview.
For example in listbox I have:
11
22
33
44
55
I would like at the press of a button that a loop starts to load one by one,each of these items like
WebView21.Source = New Uri("https://google.it" & ListBox1.Items.first & "rest of the url")
and after the webpage is loaded, it s supposed to extract it's html to check if a certain string is present with
Dim html As String
html = Await WebView21.ExecuteScriptAsync("document.documentElement.outerHTML;")
If html.Contains("Not found") Then
MsgBox("In Vacanza")
Else
MsgBox("Attivo")
End If
End Sub
after that, it goes back to the second listbox item, load the webview, check the html and so on.
My question is how can I loop the WebView in order to pick each of the items one by one and to proceed to do these little things in the while?
p.s. Once the loop arrives to the last listbox item, would it be possible to start it again from the first item?
Much thanks
edit1:
I'm trying with
Private ReadOnly resetEvent As New ManualResetEvent(False)
Async Sub scanWeb()
For Each listBoxElem As String In ListBox1.Items
resetEvent.Reset()
AddHandler WebView2.CoreWebView2.NavigationCompleted, AddressOf OnNavigationCompleted
WebView2.Source = New Uri("https://ikalogs.ru/tools/map/?page=1&server=22&world=10&state=active&search=city&allies%5B1%5D=&allies%5B2%5D=&allies%5B3%5D=&allies%5B4%5D=&nick=" & listBoxElem & "&ally=&island=&city=&x=&y=")
Await Task.Run(Sub() resetEvent.WaitOne())
RemoveHandler WebView2.CoreWebView2.NavigationCompleted, AddressOf OnNavigationCompleted
Dim html As String
html = Await WebView2.ExecuteScriptAsync("document.documentElement.outerHTML;")
If html.Contains("Not found") Then
DataGridView1.Rows.Add(listBoxElem, "IN vacanza")
Else
DataGridView1.Rows.Add(listBoxElem, "Attivo")
End If
Next
End Sub
Private Sub OnNavigationCompleted(sender As Object, e As CoreWebView2NavigationCompletedEventArgs)
resetEvent.Set()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
WebView2 = New WebView2()
WebView2.EnsureCoreWebView2Async()
End Sub
but it seems the loop doesn't wait for the process to end and it goes straight to the next listbox item...
best way is to enumerate listBox items in a for-each loop : (I added an escape way -simple mouse clic on form - to quit loop)
Dim wStop As Boolean
sub scanWeb()
Do
For Each listBoxElem As String In ListBox1.Items
WebView21.Source = New Uri("https://google.it" & listBoxElem & "rest of the url")
'etc....
Next
Loop Until wStop = True
wStop = False
end sub
'way to stop scan
Private Sub form_clic(sender As Object, e As MouseEventArgs) Handles MyBase.MouseClick
wStop = True
End Sub
*** Update *****
The webview2 control is rather made to display data, and I have no experience on it.
Also I suggest you use a simpler method, based on System.Net.WebClient() and associated with threading.
Here is a start of code that works:
Dim wStop As Boolean
Dim i As Integer = 0
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim BackProcess = New Thread(Sub() Me.scanWeb())
BackProcess.Priority = ThreadPriority.Normal
BackProcess.Start()
end sub
Sub scanWeb()
Do While Not wStop
Dim WC As New System.Net.WebClient()
'change url for your need
Dim url As String = "https://www.google.fr/search?q=" & ListBox1.Items(i)
Dim s As System.IO.Stream = WC.OpenRead(url)
Dim sr As New System.IO.StreamReader(s)
Dim html As String = sr.ReadToEnd()
If html.Contains("Not found") Then 'beginInvoke allows the back task to communicate with UI
Me.BeginInvoke(Sub() DataGridView1.Rows.Add(ListBox1.Items(i), "In vacanza"))
Else
Me.BeginInvoke(Sub() DataGridView1.Rows.Add(ListBox1.Items(i), "Attivo"))
End If
i += 1
If i > ListBox1.Items.Count - 1 Then i = 0
Loop
End Sub
'button event to stop scanning
Private Sub stopScan_Click(sender As Object, e As EventArgs) Handles stopScan.Click
wStop = True
End Sub
I currently have everything working as it should except for one thing, right now I have the user type into a textbox, press the Add button and it inserts the text into the list view, when the autotyper starts it starts a timer tick with 6000 intervals and types the list but does not go back to the beginning of the list it repeats the last known phrase.
EX:
How can I make it start back over from the beginning if there is nothing left to be typed?
My code for the timer tick
intervalTimer_Tick.Start()
Dim SeprateLine As String
Dim Separator As Integer
If ListedItems.Contains(vbLf) Then
Separator = ListedItems.IndexOf(vbLf)
SeprateLine = ListedItems.Remove(Separator)
ListedItems = ListedItems.Substring(Separator + 1)
Else
SeprateLine = ListedItems
End If
SendKeys.Send(SeprateLine)
SendKeys.Send("{ENTER}")
If ListedItems <> "" Then
End If
End Sub
My code for button
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
For Each LVI As ListViewItem In ListView1.Items
If ListedItems = "" Then
ListedItems = LVI.Text
Else
ListedItems &= vbLf & LVI.Text
End If
Next
intervalTimer_Tick.Start()
End Sub
I think it's great you've started coding in VB.NET. You are almost there, but I want to give you a suggestion. Don't store your values on your user interface - store them in code off the UI thread. Using plain old objects to keep data makes it easier to write and read. Consider a List(Of string) to hold the items, and using a ListBox and DataSource to present the data. This allows for definite separation between what is UI and what is data.
Private ReadOnly items As New List(Of String)()
Private ReadOnly timer As New System.Threading.Timer(AddressOf autoType, Nothing, -1, -1)
Private Sub AddButton_Click(sender As Object, e As EventArgs) Handles AddButton.Click
Dim s = InputBox("Add item", "Add", Nothing)
If s IsNot Nothing Then items.Add(s)
ListBox1.DataSource = Nothing
ListBox1.DataSource = items
End Sub
Private Sub RemoveButton_Click(sender As Object, e As EventArgs) Handles RemoveButton.Click
Dim si = ListBox1.SelectedIndex
If si >= 0 Then
items.RemoveAt(si)
ListBox1.DataSource = Nothing
ListBox1.DataSource = items
End If
End Sub
Private Sub StartButton_Click(sender As Object, e As EventArgs) Handles StartButton.Click
' different buttons / handlers for different intervals
timer.Change(5000, 6000) ' 5s delay before first tick, 6s between subsequent ticks
End Sub
Private Sub autoType(state As Object)
' this ticks off the UI thread, so must Control.Invoke to run on the UI
Me.Invoke(Sub() SendKeys.Send(String.Join(vbLf, items)))
End Sub
To stop it, just change the timer again
timer.Change(-1, -1)
I have a form with three textboxes in it. In my BackgroundWorker1_DoWork handler I test if any TextBox is empty and launch a MessageBox asking the user to fill in all the TextBoxes. This is done in a Try/Catch block. My problem is two fold. If the TextBoxes aren't filled in the user gets the first MessageBox and then another MessageBox when the Catch exception is thrown...so this would be the second MessageBox the user gets. In my BackGroundWorker1_RunWorkCompleted handler I test if an Exception is thrown. It never acknowledges the error and immediately executes the Else block which will be the third message box the user receives saying "Process complete." The Process Complete should not have been shown.
How do I test if there are any TextBoxes not filled in and if they're not throw 1 MessageBox telling the user to fill in all the TextBoxes? And make my RunWorkerComplete handler acknowledge the ElseIf e.Error IsNot Nothing.
Thank you for your help.
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
BackgroundWorker1.WorkerReportsProgress = True
Try
For Each cntrl As Control In Me.Controls()
If TypeOf cntrl Is TextBox Then
If CType(cntrl, TextBox).Text.Equals(String.Empty) Or (CType(cntrl, TextBox).Text = "") Then
cntrl.BackColor = Color.Yellow
MessageBox.Show("Please enter value in all fields on form" & cntrl.Name.ToString())
cntrl.Focus()
End If
End If
Next
runProgram()
Catch ex As Exception
MessageBox.Show("An error occured while trying to load this application. Please contact Maxine Hammett for assistance " &
vbNewLine & "" & vbNewLine & String.Format("Error: {0}", ex.Message))
End Try
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Cancelled = True Then
MsgBox(" Operation Cancelled ")
ProgressBar1.Value = 0
ElseIf e.Error IsNot Nothing Then
MsgBox("Error in RunWorkerComplete" & e.Error.Message)
Else
MsgBox(" Process Complete ")
Close()
End If
End Sub
Moved the control checking to the execute button. But now I get errors about the text boxes not having a path (one of the text boxes is a path to folder).
Private Sub btnExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
Dim launchProgram As Boolean = False
While launchProgram = False
For Each cntrl As Control In Me.Controls()
If TypeOf cntrl Is TextBox Then
If CType(cntrl, TextBox).Text.Equals(String.Empty) Or (CType(cntrl, TextBox).Text = "") Then
cntrl.BackColor = Color.Yellow
MessageBox.Show("Please enter value in all fields on form" & cntrl.Name.ToString())
cntrl.Focus()
launchProgram = False
Else
launchProgram = True
End If
End If
Next
End While
If launchProgram = True Then
BackgroundWorker1.RunWorkerAsync()
End If
End Sub
I suggest that you check a single text box a time and show the message if its empty:
Private Sub btnExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
For Each cntrl As TextBox In Controls.OfType(Of TextBox)
If String.IsNullOrEmpty(cntrl.Text) Then
cntrl.BackColor = Color.Yellow
MessageBox.Show("Please enter value in all fields on form" & cntrl.Name.ToString())
cntrl.Focus()
Return
Else
cntrl.BackColor = SystemColors.Window
End If
Next
BackgroundWorker1.RunWorkerAsync()
End Sub
Or maybe concatenate the names of the empty text boxes in the For..Each block if you really need to prompt the user this way:
Private Sub btnExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
Dim sb As New StringBuilder
For Each cntrl As TextBox In Controls.OfType(Of TextBox)
If String.IsNullOrEmpty(cntrl.Text) Then
If sb.Length > 0 Then sb.Append(", ")
sb.Append(cntrl.Name)
cntrl.BackColor = Color.Yellow
Else
cntrl.BackColor = SystemColors.Window
End If
Next
If sb.Length > 0 Then
MessageBox.Show("Please enter value in all fields on form" & sb.ToString())
Controls.OfType(Of TextBox).Where(Function(a) String.IsNullOrEmpty(a.Text)).FirstOrDefault?.Focus()
Return
End If
BackgroundWorker1.RunWorkerAsync()
End Sub
Otherwise, run the worker.
Good luck.
everyone, I updated my question, I am just a newbie in Visual Basic.Net and Oracle stored procedure.
I have this set of codes where I found on the internet. It works but, how can I convert this importing CSV file from fetching rows from the database using Oracle stored procedure.
Dim strRow As String() 'String array to read all fields in a row
Dim dblAmount As Double 'Variable for total amount
Dim blnReported As Boolean = True 'Flag to check progress report completed or not
'Create TextFieldParser class to parse the stock.csv file in the current location
Dim txtFile As FileIO.TextFieldParser
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Allow background operation to be cancelled
bgWorker.WorkerSupportsCancellation = True
'Allow background operation to report progress
bgWorker.WorkerReportsProgress = True
'Disable Stop Button. It is enabled only after start
'button is pressed
btnStop.Enabled = False
'set status message
lblStatus.Text = "Press Start to import data from csv."
'Add columns to the grid
dgvCSVData.Columns.Add("colNo", "No")
dgvCSVData.Columns("colNo").Width = 30
dgvCSVData.Columns.Add("colDate", "Date")
dgvCSVData.Columns("colDate").Width = 60
dgvCSVData.Columns.Add("colItem", "Item")
dgvCSVData.Columns("colItem").Width = 120
dgvCSVData.Columns.Add("colQty", "Quantity")
dgvCSVData.Columns("colQty").Width = 50
dgvCSVData.Columns.Add("colUnit", "Unit")
dgvCSVData.Columns("colUnit").Width = 30
dgvCSVData.Columns.Add("colAmt", "Amt")
dgvCSVData.Columns("colAmt").Width = 60
End Sub
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
'Disable Start button and Enable Stop
btnStart.Enabled = False
btnStop.Enabled = True
'set status message
lblStatus.Text = "Importing data from CSV file."
'Start time-consuming operation in background
Call bgWorker.RunWorkerAsync()
End Sub
Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
'Enable Start button and disable Stop
btnStart.Enabled = True
btnStop.Enabled = False
'Stop background operation
bgWorker.CancelAsync()
'set status message
lblStatus.Text = "Import cancelled. Press Start again."
End Sub
Private Sub bgWorker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgWorker.DoWork
Dim intCount As Int16 = 0
txtFile = New FileIO.TextFieldParser("stock.csv")
'Specify structure of the file
txtFile.TextFieldType = FileIO.FieldType.Delimited
txtFile.SetDelimiters(",")
'Skip header row
txtFile.ReadFields()
'Start reading data from file
While Not txtFile.EndOfData
If bgWorker.CancellationPending Then
e.Cancel = True
Exit Sub
Else
'Wait for Progress Report to finish
While Not blnReported
Application.DoEvents()
End While
'Read all field in a row into a string array
strRow = txtFile.ReadFields()
'Do some calculations and assign value to data grid
dblAmount = CDbl(strRow(3)) * CDbl(strRow(4))
'Add some sleep to simulate a long running operation
System.Threading.Thread.Sleep(500)
'Progress report pending
blnReported = False
'increment counter
intCount += 1
'Report the progress
bgWorker.ReportProgress(10, intCount)
End If
End While
End Sub
Private Sub bgWorker_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bgWorker.ProgressChanged
'Copy values to data grid
dgvCSVData.Rows.Add(strRow)
dgvCSVData.Rows(dgvCSVData.CurrentRow.Index - 1).Cells("colAmt").Value = dblAmount
pgbCopyProgress.Value = e.UserState
'Progress report finished
blnReported = True
End Sub
Private Sub bgWorker_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgWorker.RunWorkerCompleted
If e.Cancelled Or Not IsNothing(e.Error) Then
'Clear the data grid
dgvCSVData.Rows.Clear()
Else
'Progress completed
pgbCopyProgress.Value = 100
'Release txtfile
txtFile.Dispose()
btnStop.Enabled = False
btnStart.Enabled = True
End If
End Sub
Here's my code in calling the rows in the database
Public Function RESA_Checker(ByVal stores As String, ByVal bus_date As String, ByVal warehouse As String)
dt = New DataTable
bg.GetProcDataTable(connStr, "SALES_CHECKER.procedure_checker")
cmd.Parameters.Add(New OracleParameter("stores", OracleDbType.Varchar2)).Value = stores
cmd.Parameters.Add(New OracleParameter("bus_date", OracleDbType.Varchar2)).Value = bus_date
cmd.Parameters.Add(New OracleParameter("warehouse", OracleDbType.Varchar2)).Value = warehouse
cmd.Parameters.Add(New OracleParameter("O_OUTPUT", OracleDbType.RefCursor)).Direction = ParameterDirection.Output
adap_or.SelectCommand = cmd
adap_or.Fill(dt)
Return dt
ora_conn.Close()
End Function
My purpose is that the user will be informed through a dialog box with progress bar or animated gif, that the form is loading and still fetching records from the database says "Please wait"/"Searching", and prevent confusion to the user, of having thought that the form is crashed.
P.s. It would be helpful if give the links of the video tutorials.
I do hope you could help me , Thanks.
Note: You've changed your question (you should've created a new Question instead of changing your old one) and I'm not familiar with Oracle, so this information may now be irrelevant.
Like you, I'm a noobie too, but we can figure this out. There's many ways to do this, so I'll list a few. If none scratch your itch, hopefully they will have pointed you in the right direction. I also see you know what backgroundworker is, so I'll assume you know how it works or can find the resources to figure it out yourself (if not I'll link some resources to it below).
ProgressBar:
You can increment a progressbar throughout your button's process to indicate that the process is not over.
Below, when the button is pressed it searches a list for the string "Snow White". If the current string it's checking within the list is not "Snow White" the ProgressBar1 increments to show that a move title has been checked. This will loop until the "Snow White" string comes around. Then our loop will display a completed ProgressBar1 and display "Found it!"
Example Code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim moviesList As New List(Of String) From {"Cinderella", "Snow White", "Rapunzel"}
ProgressBar1.Maximum = moviesList.Count()
For Each movie In moviesList
If movie = "Snow White" Then
ProgressBar1.Value = ProgressBar1.Maximum
Label1.Text = "Found it!"
Else
ProgressBar1.Value += 1
End If
Next
End Sub
Label:
You can display a label telling the user that the button's process is still processing until it finishes.
Below, when the button is pressed it searches a list for the string "Snow White" and sets Label1 to "Loading...". If the current string it's checking within the list is not "Snow White" it continues like normal, if it is "Snow White" it will update Label1 to say "Found it!". By displaying this the user can see whether the program is loading or not.
Example Code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim moviesList As New List(Of String) From {"Cinderella", "Snow White", "Rapunzel"}
Label1.Text = "Loading..."
For Each movie In moviesList
If movie = "Snow White" Then
Label1.Text = "Found it!"
End If
Next
End Sub
Animated Gif:
You can display an animated gif while the button's process processes.
Below, when the button is pressed it searches a list for the string "Snow White" and sets PictureBox1's Visible property to True. If you have added a gif to PictureBox1 (if you don't know how I linked it in resources) you can see the PictureBox1's loading gif. When the loop finds the "Snow White" string within the moviesList it will display "Found it!" in Label1 and set PictureBox1's Visible property to False.
Example Code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim moviesList As New List(Of String) From {"Cinderella", "Snow White", "Rapunzel"}
PictureBox1.Visible = True
For Each movie In moviesList
If movie = "Snow White" Then
PictureBox1.Visible = False
Label1.Text = "Found it!"
End If
Next
End Sub
Resources:
For additional information you can use these to achieve what you want.
Animate a PictureBox:
https://www.youtube.com/watch?v=Zsvi0p9YUE4
Put a Gif in a PictureBox:
https://www.youtube.com/watch?v=igSsB_61BR8
Create a loading screen:
https://www.youtube.com/watch?v=w8mtv9zJBD0
BackgroundWorker Information:
BackgroundWorker Documentation
I'm trying to make a simple auto typer in Visual Basic. I want it to take the ListBox items and output at the user's choice of interval.
The problem is I don't know how to make the Timer's Tick event send each line and restart at the top of the list and continue to loop this way.
Form Design:
I have not listed much code because there really isn't much to list yet.
Private Sub intervalTimer_Tick(sender As Object, e As EventArgs) Handles intervalTimer.Tick
End Sub
Here is a code, but you need to replaced the ListBox with a ListView, it is the same look, this is just for the code to work.
This code is going to take each line from the ListView and output it using MsgBox using a timer that has an interval of user's choice, just remove the message box and output the result where ever you need, and you're all good :
First define this variable in your public class :
Dim ListedItems As String
Here is when you press the set button to set the interval :
Try
intervalTimer.Interval = intervalTextBox1.Text * 1000
Catch
MsgBox("The interval must be in purly seconds only!")
End Try
Here is when you press the start button :
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For Each LVI As ListViewItem In ListView1.Items
If ListedItems = "" Then
ListedItems = LVI.Text
Else
ListedItems &= vbLf & LVI.Text
End If
Next
Timer1.Start()
End Sub
Here is when the timer tick event :
Private Sub intervalTimer_Tick(sender As Object, e As EventArgs) Handles intervalTimer.Tick
intervalTimer.Stop()
Dim SeprateLine As String
Dim Separator As Integer
If ListedItems.Contains(vbLf) Then
Separator = ListedItems.IndexOf(vbLf)
SeprateLine = ListedItems.Remove(Separator)
ListedItems = ListedItems.Substring(Separator + 1)
Else
SeprateLine = ListedItems
ListedItems = ""
End If
MsgBox(SeprateLine)
If ListedItems <> "" Then
intervalTimer.Start()
End If
End Sub
Finally i hope that this will help you with what you need :)