Passing data through form with showdialog but without closing event - vb.net

I have a first form (form_notice_hashtag) called like this:
Public Sub afficher_hashtag(hashtag As String, plateforme_hashtag As String)
Dim form_notice_hashtag_1 As New form_notice_hashtag
form_notice_hashtag_1.StartPosition = FormStartPosition.CenterScreen
form_notice_hashtag_1.Show()
End Sub
In form_notice_hashtag_1, i have a button calling a 2nd form (form_recherche_thesaurus) like this:
Private Sub hashtag_thesaurus_search_button_Click(sender As Object, e As EventArgs) Handles hashtag_thesaurus_search_button.Click
Dim form_recherche_thesaurus_1 As New form_recherche_thesaurus With {
.StartPosition = FormStartPosition.Manual,
.Location = New Point(Me.Left + Me.Width, Me.Top)
}
form_recherche_thesaurus_1.ShowDialog(Me)
End Sub
In form_recherche_thesaurus, i have a datagridview listing some words. The user can select one word, then by clicking a button in form_recherche_thesaurus, the word which will be added to a textbox in form_notice_hashtag
Private Sub thesaurus_ok_button_Click(sender As Object, e As EventArgs) Handles thesaurus_ok_button.Click
Dim list_terms_array As String()
Select Case Owner.Name.ToString
Case "form_notice_hashtag"
list_terms_array = Split(Remove_Duplicates_From_Strings_With_SemiColon(form_notice_hashtag.hashtag_descripteurs_txtbox.Text & ";" & selected_term), ";")
form_notice_hashtag.hashtag_descripteurs_txtbox.Text = (String.Join(";", list_terms_array.Where(Function(s) Not String.IsNullOrEmpty(s))))
End Select
End Sub
I used a select because this mechanism would be used in the same way with other forms than form_notice_hashtag.
Problem: the textbox in form_notice_hashtag is not filled with the selected keywords. I guess it's because of the way form_notice_hashtag is called.
I can't use the solution as explained here Send values from one form to another form because i understood (maybe badly) that this solution works only if the 2nd form (form_recherche_thesaurus in my case) is closed (i.e closing was the trigger) which i don't want.
How can I proceed?

Thanks to jmcilhinney and this page of his blog, here is the solution that allows to transfer several data from a called form (form_recherche_thesaurus) to a calling form (form_notice_hashtag) without closing the called form .
Public Class form_notice_hashtag
Private WithEvents form_recherche_thesaurus_1 As form_recherche_thesaurus
Private selected_thesaurus_term As String
Private Sub form_recherche_thesaurus_1_TextBoxTextChanged(sender As Object, e As EventArgs) Handles form_recherche_thesaurus_1.TextBoxTextChanged
Dim list_terms_array As String() = Split(Remove_Duplicates_From_Strings_With_SemiColon(Me.hashtag_descripteurs_txtbox.Text & ";" & form_recherche_thesaurus_1.selected_term), ";")
Me.hashtag_descripteurs_txtbox.Text = (String.Join(";", list_terms_array.Where(Function(s) Not String.IsNullOrEmpty(s))))
End Sub
Private Sub hashtag_thesaurus_search_button_Click(sender As Object, e As EventArgs) Handles hashtag_thesaurus_search_button.Click
Dim form_recherche_thesaurus_1 As New form_recherche_thesaurus With {
.StartPosition = FormStartPosition.Manual,
.Location = New Point(Me.Left + Me.Width, Me.Top)
}
If Me.form_recherche_thesaurus_1 Is Nothing OrElse Me.form_recherche_thesaurus_1.IsDisposed Then
Me.form_recherche_thesaurus_1 = New form_recherche_thesaurus With {
.StartPosition = FormStartPosition.Manual,
.Location = New Point(Me.Left + Me.Width, Me.Top)
}
Me.form_recherche_thesaurus_1.Show()
End If
Me.form_recherche_thesaurus_1.Activate()
End Sub
End Class
Public Class form_recherche_thesaurus
Public Event TextBoxTextChanged As EventHandler
Private term_thesaurus As String
Public Property selected_term() As String
Get
Return term_thesaurus
End Get
Set(ByVal value As String)
term_thesaurus = value
End Set
End Property
Private Sub thesaurus_ok_button_Click(sender As Object, e As EventArgs) Handles thesaurus_ok_button.Click
Dim list_terms_array As String()
Me.selected_term = Me.thesaurus_search_results_datagrid.Item(0, Me.thesaurus_search_results_datagrid.CurrentRow.Index).Value
Me.DialogResult = DialogResult.OK
RaiseEvent TextBoxTextChanged(Me, EventArgs.Empty)
End Sub

Related

Datagridview form always open with row in selected state

I have two forms: frmMain and frmProduct
In the main form frmMain, I have a Datagridview1 and the buttons: tsbInsert_click, tsbAlter_click and tsbConsult_click.
When I open the main form frmMain, there is still no row in the Datagridview1 and when I click on any of the tsbAlter_click or tsbConsult_click buttons, the code displays the message "Select a product", which is correct , because there is still no product created in the register.
When I click on the tsbInsert_click button, the code opens the frmProduct to insert a record in the register and then returns to the main form frmMain, which, in the line of the Datagridview1, shows the record that was included.
The problem is that when I include a record in the register, the Datagridview1 ALWAYS returns with the state of the selected row, and the condition If DGProducts.CurrentRow Is Nothing is never true again ... so when I click on tsbAlter_click or tsbConsult_click, the "Select a product" message no longer appears and it should have since I didn't select any rows in Datagridview1.
frmMain Code:
Public Class frmMain
Private Sub tsbInsert_Click(sender As Object, e As EventArgs) Handles tsbInsert.Click
Using frm As New frmProduct("Insert", "")
frm.ShowDialog()
If frm.txtPrdCod.Text <> "" Then
DGProducts.Rows.Add(Campo(0), Campo(1), Campo(2))
End If
End Using
End Sub
Private Sub tsbAlter_Click(sender As Object, e As EventArgs) Handles tsbAlter.Click
If DGProducts.CurrentRow Is Nothing Then
MessageBox.Show("Select a product")
Exit Sub
End If
Dim codProd As String = DGProducts.CurrentRows.Cells("prdCod").Value
Using frm As New frmProduct("Alter", codProd)
frm.ShowDialog()
With DGProducts.Rows(DGProds.CurrentCell.RowIndex)
.Cells("prdCod").Value = Field(0)
.Cells("prdName").Value = Field(1)
.Cells("prdManufac").Value = Field(2)
End With
End Using
End Sub
Private Sub DGProducts_CellEnter(sender As Object, e As DataGridViewCellEventArgs) Handles DGProducts.CellEnter
With DGProducts.Rows(DGProducts.CurrentCell.RowIndex)
Campo(0) = .Cells("prdCod").Value
Campo(1) = .Cells("prdName").Value
Campo(2) = .Cells("prdManufac").Value
End With
End Sub
End Class
frmProduct code:
Public Class frmProduct
Private Sub frmProduct_Load(sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If _operation = "Alter" Then
txtPrdCod.Text = Campo(0)
txtPrdName.Text = Campo(1)
txtManufct.Text = Campo(2)
Else
txtPrdCod.Text = ""
txtPrdName.Text = ""
txtManufct.Text = ""
Enf If
End Sub
Dim _operation As String
Dim _codProd As String
Public Sub New(operation As String, codProd As String)
InitializeComponent()
Select Case operation
Case "Insert"
_operation = operation
Case "Alter"
_operation = operation
_codProd = codProd
Case Else
MessageBox.Show("Invalid option!")
Close()
End Select
End Sub
Private Sub tsbRecord_Click(sender As Object, e As EventArgs) Handles tsbRecord.Click
Field(0) = txtPrdCod.Text
Field(1) = txtPrdName.Text
Field(2) = txtManufct.Text
Me.Close()
End Sub
End Class
How do I make it so that when I add a product to the register, Datagridview1 DOES NOT return with the line in the SELECTED state and the message "Select a product" appears when I don't select a line from Datagridview1?
The command DGProducts.Rows.Add(Field(0), Field(1), Field(2)), automatically changes the value DGProducts.SelectedRows.Count to 1, so I set DGProducts.CurrentCell = Nothing after command DGProducts.Rows.Add in code:
Private Sub tsbInsert_Click(sender As Object, e As EventArgs) Handles tsbInsert.Click
Using frm As New frmProduct("Insert", "")
frm.ShowDialog()
If frm.txtPrdCod.Text <> "" Then
DGProducts.Rows.Add(Campo(0), Campo(1), Campo(2))
DGProducts.CurrentCell = Nothing
End If
End Using
End Sub

How to show records added to datagridview in real time

A co-worker needs to search our network and her File Explorer search does not work well. I threw this app together quickly to allow her to search and it works well. The results are written to a datagridview, but the results are not shown until the search is complete.
I would like the datagridview to show records as they are added and allow her to cancel the search if she wants.
Using a backgroundworker, I tried to refresh the grid, but as soon as it finds a match, the code stops running. There are no errors, it just stops running.
So how can I get the grid to update as it continues to search?
Public dtResults As DataTable
Dim myDataSet As New DataSet
Dim myDataRow As DataRow
Dim colType As DataColumn
Dim colResult As DataColumn
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dtResults = New DataTable()
colType = New DataColumn("Type", Type.GetType("System.String"))
colResult = New DataColumn("Search Result", Type.GetType("System.String"))
dtResults.Columns.Add(colType)
dtResults.Columns.Add(colResult)
DataGridView1.DataSource = dtResults
DataGridView1.Columns(1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
End Sub
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
btnSearch.Enabled = False
sbStatusBar.Text = "Searching..."
dtResults.Clear()
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
LoopSubFolders(txtSearchLocation.Text)
End Sub
Public Sub LoopSubFolders(sLocation As String)
Dim di = New DirectoryInfo(sLocation)
Dim mySearchterm As String = LCase(txtSearchTerm.Text)
Dim fiArr As FileInfo() = di.GetFiles()
Dim sSearchTarget As String
sbStatusBar.Text = "Searching " & sLocation
'Search File names in
If cbFileNames.Checked = True Then
For Each myFile In fiArr
sSearchTarget = LCase(myFile.Name)
If sSearchTarget.Contains(mySearchterm) Then
myDataRow = dtResults.NewRow()
myDataRow(dtResults.Columns(0)) = "File"
myDataRow(dtResults.Columns(1)) = Path.Combine(sLocation, myFile.Name)
dtResults.Rows.Add(myDataRow)
End If
Next
End If
For Each d In Directory.GetDirectories(sLocation)
If cbFolderNames.Checked = True Then
sSearchTarget = LCase(d)
If sSearchTarget.Contains(mySearchterm) Then
myDataRow = dtResults.NewRow()
myDataRow(dtResults.Columns(0)) = "Folder"
myDataRow(dtResults.Columns(1)) = d
dtResults.Rows.Add(myDataRow)
End If
End If
LoopSubFolders(d)
Next
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
btnSearch.Enabled = True
sbStatusBar.Text = "Complete"
DataGridView1.DataSource = Nothing
DataGridView1.DataSource = dtResults
DataGridView1.Columns(1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
End Sub
Here's an example of how you might do it using the suggested ReportProgress method and ProgressChanged event:
Private table As New DataTable
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Configure table here.
DataGridView1.DataSource = table
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Setup UI here.
'Note that you MUST pass in the TextBox data as you MUST NOT touch the UI directly on the secondary thread.
BackgroundWorker1.RunWorkerAsync({TextBox1.Text, TextBox2.Text})
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'Get the data passed in and separate it.
Dim arguments = DirectCast(e.Argument, String())
Dim folderPath = arguments(0)
Dim searchTerm = arguments(1)
SearchFileSystem(folderPath, searchTerm)
End Sub
Private Sub SearchFileSystem(folderPath As String, searchTerm As String)
For Each filePath In Directory.GetFiles(folderPath)
If filePath.IndexOf(searchTerm, StringComparison.InvariantCultureIgnoreCase) <> -1 Then
'Update the UI on the UI thread.
BackgroundWorker1.ReportProgress(0, {"File", filePath})
End If
Next
For Each subfolderPath In Directory.GetDirectories(folderPath)
If subfolderPath.IndexOf(searchTerm, StringComparison.InvariantCultureIgnoreCase) <> -1 Then
'Update the UI on the UI thread.
BackgroundWorker1.ReportProgress(0, {"Folder", subfolderPath})
End If
SearchFileSystem(subfolderPath, searchTerm)
Next
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
'Get the data passed out and separate it.
Dim data = DirectCast(e.UserState, String())
'Update the UI.
table.Rows.Add(data)
End Sub
Note that you should NEVER touch the UI directly in the DoWork event handler or a method called from it. ONLY touch the UI on the UI thread. That means that the text in your TextBoxes must be extracted BEFORE calling RunWorkerAsync. You can eithewr pass the Strings in as arguments or you can assign them to fields and access them from there on any thread. Don't EVER access a member of a control on other than the UI thread. Some times it will work, sometimes it will appear to work but not do as intended and sometimes it will crash your app. So that you don't have to remember which specific scenarios cause which result, avoid such scenario altogether.
I haven't tested this code so I'm not sure but you may have to call Refresh on the grid or the form after adding the new row to the DataTable.
Variables
Well, let's start from the top with some class level variables:
'Notice the enabled properties.
Private WithEvents BackgroundWorker1 As New BackgroundWorker With {.WorkerReportsProgress = True, .WorkerSupportsCancellation = True}
'To monitor the cancellation, set by the Cancel Button.
Private bgwCancel As Boolean = False
'The DGV source.
Private dtResults As New DataTable
'The start directory.
Private startDir As String
'The search keyword.
Private searchWord As String
'Whether to search the sub directories, from a check box for example.
Private includeSubDirectories As Boolean = True
'Whether to search the files, from another check box.
Private includeFiles As Boolean = True
The Constructor
Prepare your DGV and whatever else you need here.
Sub New()
dtResults.Columns.Add(New DataColumn("Type", Type.GetType("System.String")))
dtResults.Columns.Add(New DataColumn("Search Result", Type.GetType("System.String")))
DataGridView1.DataSource = dtResults
DataGridView1.Columns(1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
'Make sure you add the image column after binding the data source.
Dim imgCol As New DataGridViewImageColumn(False)
With imgCol
.Image = Nothing
.Name = "imgCol"
.HeaderText = ""
.Width = 50
.DefaultCellStyle.NullValue = Nothing
End With
DataGridView1.Columns.Insert(0, imgCol)
End Sub
Iterator
Now, let's write the search routine. I'd do that through an Iterator function:
Private Iterator Function IterateFolders(startDir As String, includeFiles As Boolean, includeSubDir As Boolean) As IEnumerable(Of String)
For Each dirName In IO.Directory.EnumerateDirectories(startDir)
Yield dirName
If includeFiles Then
For Each fileName In IO.Directory.EnumerateFiles(startDir)
Yield fileName
Next
End If
If includeSubDir Then
For Each subDir In IterateFolders(dirName, includeFiles, includeSubDir)
Yield subDir
Next
End If
Next
End Function
The Main Thread Updater
A routine called by the worker's thread to update the DataTable and any control that belongs to the main thread:
Private Sub AddSearchResult(path As String)
If InvokeRequired Then
Invoke(Sub() AddSearchResult(path))
Else
dtResults.Rows.Add(If(IO.File.Exists(path), "File", "Folder"), path)
sbStatusBar.Text = $"Searching {path}"
End If
End Sub
Start
In the click event of the start button, do the necessary validations, assign the values to their variables, and start the back ground worker:
If String.IsNullOrEmpty(txtSearchKeyword.Text) Then Return
If String.IsNullOrEmpty(txtSearchLocation.Text) Then Return
bgwCancel = False
dtResults.Rows.Clear()
startDir = txtSearchLocation.Text
searchWord = txtSearchKeyword.Text.ToLower
includeSubDirectories = chkIncludeSubDirs.Checked
includeFiles = chkFiles.Checked
btnSearch.Enabled = False
sbStatusBar.Text = "Searching..."
BackgroundWorker1.RunWorkerAsync()
Cancel
To cancel the search, in the click event of the cancel button I presume, True the bgwCancel variable:
bgwCancel = True
The BackgroundWorker - DoWork
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For Each item As String In IterateFolders(startDir, includeFiles, includeSubDirectories)
If bgwCancel Then
BackgroundWorker1.CancelAsync()
Return
End If
If item.ToLower.Contains(searchWord) Then
AddSearchResult(item)
End If
Threading.Thread.Sleep(100)
Next
End Sub
Note that, Its good practice to give a lengthy routine a BREATH through the Sleep(ms) method of that thread.
The BackgroundWorker - ProgressChanged
I don't think you need it here.
The BackgroundWorker - RunWorkerCompleted
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If bgwCancel Then
sbStatusBar.Text = "Canceled!"
MessageBox.Show("Canceled by you!")
ElseIf e.Error IsNot Nothing Then
sbStatusBar.Text = "Error!"
MessageBox.Show(e.Error.Message)
Else
sbStatusBar.Text = "Complete"
'YOU DO NOT NEED TO DO THIS. Remove the following
'DataGridView1.DataSource = Nothing
'DataGridView1.DataSource = dtResults
'DataGridView1.Columns(1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
End If
btnSearch.Enabled = True
End Sub
The Image Column
Handle the RowsAdded event of the DGV as follow:
Private Sub DataGridView1_RowsAdded(sender As Object, e As DataGridViewRowsAddedEventArgs) Handles DataGridView1.RowsAdded
If DataGridView1.Columns.Count < 3 Then Return
'if you want to get rid of the default x image.
If e.RowIndex = 0 Then
DataGridView1.Rows(e.RowIndex).Cells("imgCol").Value = Nothing
End If
Dim path As String = DataGridView1.Rows(e.RowIndex).Cells(2).Value?.ToString
If Not String.IsNullOrEmpty(path) Then
If IO.File.Exists(path) Then
DataGridView1.Rows(e.RowIndex).Cells("imgCol").Value = Icon.ExtractAssociatedIcon(path).ToBitmap
Else
DataGridView1.Rows(e.RowIndex).Cells("imgCol").Value = My.Resources.Folder
End If
End If
End Sub
Where the My.Resources.Folder is an icon file of your choice for the folder entries.
Good luck.

VB.NET: Code runs without error, but does not add item to listbox

I've got this embedded CMD on my form which I created using another person's code and everything works right. Inside one of the Private Subs (that seems to run every time a new line is written in the CMD output textbox), I've got a line which adds a item to a listbox (listboxs name is txtPlayerList) on another form labelled Status.
When this area of the code runs, it doesn't throw up any errors (and if I put a msgbox() on the same line, the msgbox() works). If I put the add to listbox line on form_load it works perfectly?
Here is my code, I've included everything from that form just in case (it is in the third sub from the top with the asterisks and comment "Get players and maybe other stuff as well"
Imports System.IO
Public Class Console
Public WithEvents MyProcess As Process
Private Delegate Sub AppendOutputTextDelegate(ByVal text As String)
Public LastLine As String
Public LastLineFormatted As String
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim LocalpathParent As String = Application.StartupPath() + "\MCserver"
'loads embed cmd
Me.AcceptButton = ExecuteButton
MyProcess = New Process
With MyProcess.StartInfo
.FileName = "CMD.EXE"
.UseShellExecute = False
.CreateNoWindow = True
.RedirectStandardInput = True
.RedirectStandardOutput = True
.RedirectStandardError = True
.WorkingDirectory = LocalpathParent
End With
MyProcess.Start()
MyProcess.BeginErrorReadLine()
MyProcess.BeginOutputReadLine()
AppendOutputText("Process Started at: " & MyProcess.StartTime.ToString)
'Resize with parent mdi container. Needs to be anchored & StartPosition = manual in properties
Me.WindowState = FormWindowState.Maximized
End Sub
Private Sub MyProcess_ErrorDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles MyProcess.ErrorDataReceived
AppendOutputText(vbCrLf & "Error: " & e.Data)
End Sub
Private Sub MyProcess_OutputDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles MyProcess.OutputDataReceived
AppendOutputText(vbCrLf & e.Data)
'*****************************************
'Get Players and maybe other stuff as well
'*****************************************
LastLine = Me.OutputTextBox.Lines.Last
If Status.ServerStarted = True Then
If Me.LastLine.Contains(" joined the game") Then
LastLineFormatted = Me.LastLine
LastLineFormatted = LastLineFormatted.Replace(" joined the game", "")
'***THIS LINE BELOW WORKS IN FORM LOAD, BUT NOT HERE FOR SOME REASON???***
Status.txtPlayersList.Items.Add(LastLineFormatted)
MsgBox("add lastlineformatted")
ElseIf Me.LastLine.Contains(" left the game") Then
LastLineFormatted = Me.LastLine
LastLineFormatted = LastLineFormatted.Replace(" left the game", "")
Status.txtPlayersList.Items.Remove(LastLineFormatted)
End If
End If
End Sub
Private Sub ExecuteButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExecuteButton.Click
MyProcess.StandardInput.WriteLine(InputTextBox.Text)
MyProcess.StandardInput.Flush()
InputTextBox.Text = ""
End Sub
Private Sub AppendOutputText(ByVal text As String)
If OutputTextBox.InvokeRequired Then
Dim myDelegate As New AppendOutputTextDelegate(AddressOf AppendOutputText)
Try
Me.Invoke(myDelegate, text)
Catch
End Try
Else
Try
OutputTextBox.AppendText(text)
Catch
End Try
End If
End Sub
End Class
EDIT: Below is the code I have for form1 per request
'code
Public Class Form1
Public Localpath As String
Public Downloadpath As String
Public LocalpathParent As String
'when this form is closing, send stop to console to make sure it has closed and saved
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Console.MyProcess.StandardInput.WriteLine("stop") 'send an EXIT command to the Command Prompt
Application.Exit()
End
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'load stuff in background n stuff
Me.Show()
Me.Focus()
Configure.Show()
Configure.Hide()
Status.Show()
Status.Hide()
Console.Show()
Console.Hide()
End Sub
'CONSOLE.form
Private Sub ConsoleToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles ConsoleToolStripMenuItem1.Click
'Hide all forms
Status.Hide()
Configure.Hide()
'Shown Form that you want to load
Console.Opacity = 100
Console.Show()
WindowState = FormWindowState.Normal
Console.MdiParent = Me
Console.OutputTextBox.SelectionStart = Console.OutputTextBox.Text.Length
Console.OutputTextBox.ScrollToCaret()
End Sub
'STATUS.form
Private Sub StatusToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles StatusToolStripMenuItem1.Click
'hide all forms
Console.Hide()
Configure.Hide()
'Show Form that you want to load
Status.Opacity = 100
Status.Show()
WindowState = FormWindowState.Maximized
Configure.Size = Me.Size
Status.MdiParent = Me
End Sub
'CONFIGURE.form
Private Sub ConfigurationToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles ConfigurationToolStripMenuItem1.Click
'hide all forms
Status.Hide()
Console.Hide()
'Show form that you want to load
Configure.Opacity = 100
Configure.Show()
WindowState = FormWindowState.Maximized
Configure.Size = Me.Size
Configure.MdiParent = Me
End Sub
End Class
'code
It seems that your original code to create an embeded CMD window was interfering with the code to update the listbox in another mdi child. After finding another way to embed a cmd console, and some fiddling around, It seems to be working Ok. I haven't been able to test pure server output yet though.
THere have been quite a few changes to the code that are too big to post here, but the Alternative embedded CMD is this.
Place this in general form declarations
'command prompt variables
Private strResults As String
Private intStop As Integer
Private swWriter As System.IO.StreamWriter
Friend thrdCMD As System.Threading.Thread
Private Delegate Sub cmdUpdate()
Private uFin As New cmdUpdate(AddressOf UpdateText)
Public WithEvents procCMDWin As New Process
This in your form_load Sub
thrdCMD = New System.Threading.Thread(AddressOf Prompt)
thrdCMD.IsBackground = True
thrdCMD.Start()
and these declarations within your form Class
Private Sub Prompt()
AddHandler procCMDWin.OutputDataReceived, AddressOf CMDOutput
AddHandler procCMDWin.ErrorDataReceived, AddressOf CMDOutput
procCMDWin.StartInfo.RedirectStandardOutput = True
procCMDWin.StartInfo.RedirectStandardInput = True
procCMDWin.StartInfo.CreateNoWindow = True
procCMDWin.StartInfo.UseShellExecute = False
procCMDWin.StartInfo.FileName = "cmd.exe"
procCMDWin.StartInfo.WorkingDirectory = LocalpathParent
procCMDWin.Start()
procCMDWin.BeginOutputReadLine()
swWriter = procCMDWin.StandardInput
Do Until (procCMDWin.HasExited)
Loop
procCMDWin.Dispose()
End Sub
Private Sub UpdateText()
OutputTextBox.Text += strResults
OutputTextBox.SelectionStart = OutputTextBox.TextLength - 1
InputTextBox.Focus()
intStop = OutputTextBox.SelectionStart
OutputTextBox.ScrollToCaret()
If OutputTextBox.Lines.Count > 2 Then
LastLine = OutputTextBox.Lines.ElementAt(OutputTextBox.Lines.Count - 2)
If Status.ServerStarted = True Then
'get element 1 of split
If LastLine.Contains(" joined the game") Then
LastLineFormatted = ExtractName(LastLine, " joined the game")
'If listlineformatted.contains(Players.allitems) then do
Status.txtPlayersList.Items.Add(LastLineFormatted)
Status.Show()
ElseIf Me.LastLine.Contains(" left the game") Then
LastLineFormatted = ExtractName(LastLine, " left the game")
'If listlineformatted.contains(Players.allitems) then do
Status.txtPlayersList.Items.Remove(LastLineFormatted)
MsgBox("remove lastlineformatted")
End If
End If
End If
End Sub
Private Function ExtractName(unformattedString As String, stringToRemove As String) As String
Dim temp As String = Split(unformattedString, "Server]")(1).ToString
ExtractName = temp.Replace(stringToRemove, "")
End Function
Private Sub CMDOutput(ByVal Sender As Object, ByVal OutputLine As DataReceivedEventArgs)
strResults = OutputLine.Data & Environment.NewLine
Invoke(uFin)
End Sub

access to new dynamically controls in vb.net

First of all excuse me for my poor grammar and vocabulary :)
please see this source and run it:
Public Class Form1
Public pointX As Integer
Public pointY As Integer = 32
Public dynamicText As TextBox
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
pointX = 330
For i = 1 To 4
dynamicText = New Windows.Forms.TextBox
dynamicText.Name = "T" + Trim(Str(i))
dynamicText.Text = ""
dynamicText.Location = New Point(pointX, pointY)
dynamicText.Size = New Size(100, 20)
Me.Controls.Add(dynamicText)
pointX = pointX - 106
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
pointX = 330
pointY = pointY + 26
For i = 1 To 4
dynamicText = New Windows.Forms.TextBox
dynamicText.Name = "T" + Trim(Str(i))
dynamicText.Text = ""
dynamicText.Location = New Point(pointX, pointY)
dynamicText.Size = New Size(100, 20)
Me.Controls.Add(dynamicText)
pointX = pointX - 106
AddHandler dynamicText.Click, AddressOf printHello1
Next
End Sub
Private Sub printHello1(ByVal sender As System.Object, ByVal e As System.EventArgs)
MsgBox(dynamicText.Name)
If dynamicText.Name = "T1" Then MsgBox("Oh! this is T1")
End Sub
End Class
why If never is not true?!
why MsgBox(dynamicText.Name) always return T4?!
i want all controlls to be access by name or array of names.
please help me thank you. :)
The global variable dynamicText takes the value of the last TextBox added in the loop inside the Button1_Click event. This happens to be the control named T4. You don't really need a global variable in this case. You can cast the sender parameter to a TextBox instance because the sender parameter is the control that has raised the event.
Private Sub printHello1(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim txt = CType(sender, "TextBox")
if txt IsNot Nothing then
MsgBox(txt.Name)
If txt.Name = "T1" Then MsgBox("Oh! this is T1")
End If
End Sub
You also don't need to recreate the controls again in the button click event. The action executed in the form load event is enough (You could add the AddHandler there). Global variables are dangerous, avoid them when possible.
See if this is acceptable. Place a panel at the bottom of your form, set Dock to Bottom, add a single button to the panel and a TextBox. Place a FlowLayoutPanel onto the form, Dock = Fill, AutoScroll = True.
The code below creates the amount of TextBox controls as inputted into TextBox. Each newly created TextBox a click event is added with simple logic.
Form code
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim count As Integer = 0
If Integer.TryParse(TextBox1.Text, count) Then
Dim demo = New TextBoxCreate(FlowLayoutPanel1, "Demos", count)
demo.CreateTextBoxes()
End If
End Sub
End Class
Class code (add a new class to the project, name it TextBoxCreate.vb)
Public Class TextBoxCreate
Public Property TextBoxes As TextBox()
Public Property TextBoxBaseName As String
Public Property TextBoxCount As Integer
Public Property ParentControl As Control
Public Sub New(
ByVal ParentControl As Control,
ByVal BaseName As String,
ByVal Count As Integer)
Me.ParentControl = ParentControl
Me.TextBoxBaseName = BaseName
Me.TextBoxCount = Count
End Sub
Public Sub CreateTextBoxes()
Dim Base As Integer = 10
TextBoxes = Enumerable.Range(0, TextBoxCount).Select(
Function(Indexer)
Dim b As New TextBox With
{
.Name = String.Concat(TextBoxBaseName, Indexer + 1),
.Text = (Indexer + 1).ToString,
.Width = 150,
.Location = New Point(25, Base),
.Parent = Me.ParentControl,
.Visible = True
}
AddHandler b.Click, Sub(sender As Object, e As EventArgs)
Dim tb As TextBox = CType(sender, TextBox)
If tb.Name = TextBoxBaseName & "1" Then
tb.Text = "Got it"
Else
MessageBox.Show(tb.Name)
End If
End Sub
Me.ParentControl.Controls.Add(b)
Base += 30
Return b
End Function).ToArray
End Sub
End Class

Refreshing Listbox in VB.Net

I was wondering if there is any way to refresh the cont numbers in a listbox
i am adding data with the code
ListBox1.Items.Add
I have set up as button to remove selected data with the code:
For i As Integer = ListBox1.SelectedIndices.Count - 1 To 0 Step -1
ListBox1.Items.RemoveAt(ListBox1.SelectedIndices.Item(i))
Next
say my list box is like this
Zach
Barry
John
Nick
Brodie
if i deleted say barry how can i make the numbers change so john would be 2. etc
The BindingList can be helpful here since it can listen for changes in the list.
For example, create a Person class and override the ToString function to show the rank and the name.
Public Class Person
Property Name As String
Property Rank As Integer
Public Overrides Function ToString() As String
Return Rank & ". " & Name
End Function
End Class
In your form, declare the list and add the event handler:
Private people As New BindingList(Of Person)
Public Sub New()
InitializeComponent()
AddHandler people.ListChanged, AddressOf people_ListChanged
people.Add(New Person() With {.Name = "Zach"})
people.Add(New Person() With {.Name = "Barry"})
people.Add(New Person() With {.Name = "John"})
people.Add(New Person() With {.Name = "Nick"})
people.Add(New Person() With {.Name = "Brodie"})
ListBox1.DataSource = people
End Sub
Private Sub people_ListChanged(sender As Object, e As ListChangedEventArgs)
For i As Integer = 0 To people.Count - 1
people(i).Rank = i + 1
Next
End Sub
The ListChanged event just updates the ranking of each member as they as slotted in the list, which will automatically update the ListBox since the DataSource is coming from the people list.
A simple delete button to test the list, and the rankings are automatically updated in the people list, which automatically updates the ListBox:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If ListBox1.SelectedIndex > -1 Then
people.Remove(ListBox1.SelectedItem)
End If
End Sub
If you have some idea of GDI+ drawing, a more interesting approach is to set your ListBox's DrawMode to OwnerDrawFixed mode and listen to ListBox's DrawItem event, something like this:
C#
private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
e.Graphics.DrawString((e.Index + 1).ToString() + ". " + listBox1.Items[e.Index].ToString(), listBox1.Font, Brushes.Black, e.Bounds);
}
VB.NET
Private Sub listBox1_DrawItem(sender As Object, e As DrawItemEventArgs)
e.DrawBackground()
e.Graphics.DrawString((e.Index + 1).ToString() & ". " & listBox1.Items(e.Index).ToString(), listBox1.Font, Brushes.Black, e.Bounds)
End Sub
Adding or removing any items to the ListBox will automatically renumber all the items.
You can use a List of string combined with the ListBox.
Dim NamesList1 As New List(Of String)
Private Sub Form_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
NamesList1.AddRange({"Zach", "Barry", "John", "Nick", "Brodie"})
FillListBoxItems()
End Sub
Private Sub FillListBoxItems()
ListBox1.Items.Clear()
For i As Integer = 0 To NamesList1.Count - 1
ListBox1.Items.Add(i + 1 & ". " & NamesList1.Item(i))
Next
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
For i As Integer = ListBox1.SelectedIndices.Count - 1 To 0 Step -1
NamesList1.RemoveAt(ListBox1.SelectedIndices.Item(i))
Next
FillListBoxItems()
End Sub