Why does Windows.Media.VisualTreeHelper.GetChild(...) exit the sub? - vb.net

I have a vb application with a listview.
I was testing and ended up with this sub for my dragover event:
Private Sub ListView1_DragOver(sender As Object, e As DragEventArgs) Handles ListView1.DragOver
XToolStripLabel.Text = "X:" & e.X
YToolStripLabel.Text = "Y:" & e.Y
Dim Insertion As Integer = GetInsertion(MousePosition, ListView1)
SelectionTestTSlabel.Text = "SEL " & Insertion
If CurrentlyDragging Then
Dim gr As Graphics = ListView1.CreateGraphics
Windows.Media.VisualTreeHelper.GetChild(New Windows.DependencyObject(), 0) 'I know this seems like it doesn't do much
MsgBox("") 'I actually added this later because the rest of the code did not run normally.
Dim InsertionY As Integer = 24 + (Insertion * TestItemHeight)
If MyLastInsPoint = Insertion Then
Else
ListView1.Refresh()
gr.DrawLine(New Pen(Color.Gray, 3), New Point(0, InsertionY), New Point(ListView1.Width, InsertionY))
End If
MyLastInsPoint = Insertion
End If
End Sub
I realized that the MsgBox("") doesn't popup a message box then i spammed breakpoints on the whole sub.
The sub ran as normal but after this line,
Windows.Media.VisualTreeHelper.GetChild(New Windows.DependencyObject(), 0)
the program returned to the form and did not execute the MsgBox("") line.
What's wrong with the line? The program did not even stop at the End Sub breakpoint.

New Windows.DependencyObject() has no children, so index 0 is not available
See the remaks on MSDN
Call the GetChildrenCount method to determine the total number of
child elements of a parent visual.
The value of reference can
represent either a Visual or Visual3D object, which is why the common
base type DependencyObject is used here as a parameter type.

Related

Remove specific row of TableLayoutPanel using dynamically created button of each row

So I am making a function that will populate the TableLayoutPanel from FileDialog Result then make a delete button for each row using a loop. Here's the code
Private PathtoFile1 As New List(Of String) 'this will contain all the selected file in the dialogwindow
Private rowLineDrawing As Integer = 0
Private selectedfilecountLineDrawing As Integer
Public Function AttachFileLineDrawing(TLP As TableLayoutPanel)
Dim dr = OpenFileDialog1.ShowDialog
If (dr = System.Windows.Forms.DialogResult.OK) Then
selectedfilecountLineDrawing = OpenFileDialog1.FileNames.Count
For Each FileName In OpenFileDialog1.FileNames
Try
Console.WriteLine(FileName.ToString)
PathtoFile1.Add(FileName.ToString)
Catch SecEx As Security.SecurityException
MessageBox.Show("Security error. Please contact your administrator for details.\n\n" &
"Error message: " & SecEx.Message & "\n\n" &
"Details (send to Support):\n\n" & SecEx.StackTrace)
Catch ex As Exception
'Could Not Load the image - probably permissions-related.
MessageBox.Show(("Cannot display the image: " & FileName.Substring(FileName.LastIndexOf("\"c)) &
". You may not have permission to read the file, or " + "it may be corrupt." _
& ControlChars.Lf & ControlChars.Lf & "Reported error: " & ex.Message))
End Try
Next
'MAKE SOMETHING HERE TO DISPLAY THE SELECTED ITEMS IN THE TABLELAYOUTPANEL OF THE SUBMIT PROGRESS
TLP.Controls.Clear()
TLP.RowCount = 0
rowLineDrawing = 0
For Each Path In PathtoFile1
Dim filepath As New Label
filepath.Text = Path
filepath.Width = Val(360)
'this button is for previewing the file
Dim btnPreview As New Button
AddHandler btnPreview.Click,
Sub(s As Object, e As EventArgs)
Dim btn = CType(s, Button)
MsgBox("This is Preview")
End Sub
'This button is for removing rows in the tablelayoutpanel
Dim btnRmv As New Button
Dim StringToIndex As String = Path 'THIS CATCHES EVERY PATH IN THE LOOP AND STORE IT TO THE VARIABLE WHICH THEN BE USED AS A COMPARABLE PARAMETER FOR THE INDEX SEARCH
Dim index = PathtoFile1.IndexOf(Path)
AddHandler btnRmv.Click,
Sub(s As Object, e As EventArgs)
Dim btn = CType(s, Button)
MsgBox(index)
PathtoFile1.RemoveAt(index) 'THIS LINE OF CODE REMOVE THE SPECIFIC ITEM IN THE LIST USING THE BTNRMV CLICK
'MAKE SOMETHING HERE TO REMOVE THE ROW IN THE TABLELAYOUTAPANEL
End Sub
TLP.SuspendLayout()
TLP.RowStyles.Add(New RowStyle(SizeType.Absolute, 20))
TLP.Controls.Add(filepath, 0, rowLineDrawing)
TLP.Controls.Add(btnPreview, 1, rowLineDrawing)
TLP.Controls.Add(btnRmv, 2, rowLineDrawing)
TLP.ResumeLayout()
rowLineDrawing -= -1
Next
End If
End Function
So I am trying to remove the row in the TableLayoutPanel together with the dynamic control. My approach is removing the selected item in the list and I achieved it properly but can't remove the row in the TableLayoutPanel. Any help is much appreciated!
EDIT
I have tried to use the provided module above but got this error
And got this error
Here is an extension method that will enable you to remove any row from a TableLayoutPanel by index:
Imports System.Runtime.CompilerServices
Public Module TableLayoutPanelExtensions
<Extension>
Public Sub RemoveRowAt(source As TableLayoutPanel, index As Integer)
If index >= source.RowCount Then
Throw New ArgumentOutOfRangeException(NameOf(index),
index,
"The row index must be less than the number of rows in the TableLayoutPanel control.")
End If
'Remove the controls in the specified row.
For columnIndex = 0 To source.ColumnCount - 1
Dim child = source.GetControlFromPosition(columnIndex, index)
If child IsNot Nothing Then
child.Dispose()
End If
Next
'Move controls below the specified row up.
For rowIndex = index + 1 To source.RowCount - 1
For columnIndex = 0 To source.ColumnCount - 1
Dim child = source.GetControlFromPosition(columnIndex, rowIndex)
If child IsNot Nothing Then
source.SetCellPosition(child, New TableLayoutPanelCellPosition(columnIndex, rowIndex - 1))
End If
Next
Next
'Remove the last row.
source.RowCount -= 1
End Sub
End Module
I tested that on 3 column by 4 row TableLayoutPanel containing a Label in each cell executing the following code twice:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TableLayoutPanel1.RemoveRowAt(1)
End Sub
The result was as expected, i.e. removing the second-from-top row each time. You may need to fiddle a bit more depending on what you want to happen row heights. I had the row heights set to equal percentages so the remaining rows grew proportionally to fill the space. If you want something different, you can add code accordingly. Note that you could create an almost identical method for removing columns.

Serial Communication stops working when loop is started

I have problem with serial data communication if I started a loop it is not updating the data from my weighing scale. I can't figure out how to continue the communication as well as to run the loop. The logic of my code will be in the loop so I could check the value from my integer and compare it to the data from serial data (Weighing Scale)
Private Sub conWeight_DataReceived(sender As System.Object, e As System.IO.Ports.SerialDataReceivedEventArgs) Handles conWeight.DataReceived
receivedText(conWeight.ReadExisting())
End Sub
Private Sub receivedText(ByVal [text] As String)
If Me.lblWeight.InvokeRequired Then
Dim x As New SetTextCallback(AddressOf receivedText)
Me.Invoke(x, New Object() {(text)})
Else
Dim reverseString As String = [text]
Dim revString As String = StrReverse(reverseString)
Dim clean As String
clean = revString.Replace("=", "")
Me.lblWeight.Text = clean 'append text
End If
End Sub
'this is part with loop
If binWeight = 0 Then
targetweight = CInt(txtbSilo1.Text) + CInt(txtbSilo2.Text) + CInt(txtbSilo3.Text) + CInt(txtbSilo4.Text)
If CInt(txtbSilo1.Text) > 0 Then
currentWeight = CInt(txtbSilo1.Text)
frmAutomaticControl.conControl.Open()
frmAutomaticControl.conControl.Write("motr1")
frmAutomaticControl.conControl.Close()
MsgBox("check")
Do
If binWeight >= currentWeight Then
frmAutomaticControl.conControl.Open()
frmAutomaticControl.conControl.Write("moto1")
frmAutomaticControl.conControl.Close()
Exit Do
End If
Loop
Else
End If
BunifuFlatButton1.Enabled = True
Else
MsgBox("Empty The Bin")
End If
just a couple of ideas.
1. Throw that part of the code into a background worker.
2. Cheese it and throw in an application.doevents.
3. Create a global variable that'll capture the output of each iteration of your loop that'll then feed it where it needs to go.
Just one line of code is all you need. In your loop put this above everything else.
Application.DoEvents()

MP3 Player Random Function doesn't Work

I just started my first project and i'm trying to make a mp3 player.
Unfortunately My "Random" causes the whole program to crash when i'm trying to open a song.
This is the error produced in Visual Studio Ultimate 2013:
An exception of type 'System.ArgumentOutOfRangeException' occurred in System.Windows.Forms.dll but was not handled in user code
Additional information: InvalidArgument=Value of '1' is not valid for 'index'.
Please tell me what's wrong with my code, This is a link to my repository in Github, Thanks!
https://github.com/LefanTan/MP3_Player/tree/Mp3
Edit:
This line is the code that was producing the error-
Private Sub wpm_PlayStateChange(sender As Object, e As AxWMPLib._WMPOCXEvents_PlayStateChangeEvent) Handles wpm.PlayStateChange While shuffle.CheckOnClick = True tempInt = r.Next(0, ListBox1.Items.Count + 1) wpm.URL = ListBox1.Items(tempInt) End While While RepeatToolStripMenuItem1.CheckOnClick = True wpm.URL = currentSong End While End Sub
I assume this is the problematic sub:
Private Sub wpm_PlayStateChange(sender As Object, e As AxWMPLib._WMPOCXEvents_PlayStateChangeEvent) Handles wpm.PlayStateChange
While shuffle.CheckOnClick = True
tempInt = r.Next(0, ListBox1.Items.Count + 1)
wpm.URL = ListBox1.Items(tempInt)
End While
While RepeatToolStripMenuItem1.CheckOnClick = True
wpm.URL = currentSong
End While
End Sub
The line
tempInt = r.Next(0, ListBox1.Items.Count + 1)
Should be
tempInt = r.Next(0, ListBox1.Items.Count)
The syntax of this function is Random.Next(min, max) where min is inclusive and max is exclusive i.e. max isn't included in generating the random number. Because you added one to ListBox1.Items.Count (which is going to be the upper bound of the collection plus one), you went out of range.
Please Check your iteration code.
think the problem is, that your index increases
For Each item As String In My.Computer.FileSystem.GetFiles(txtfolder.Text, Microsoft.VisualBasic.FileIO.SearchOption.SearchTopLevelOnly, "*.mp3")
ListBox1.Items.Add(item)
Next

ArgumentOutOfRangeException when trying to clear combobox

I'm having the following error message appear when trying to run .Clear() on my combobox:
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in System.Windows.Forms.dll
{"InvalidArgument=Value of '-1' is not valid for 'index'.
Parameter name: index"}
The strange part is, it does the .Clear() before going to the new 'page' in the application, and it works without a problem. Once I'm on the 'page', draw the items in the combobox and try to go to the next 'page' of the application, it calls the function with the clear once again and blows up when it gets to the .Clear(). If I comment out the cbo.DrawMode = DrawMode.OwnerDrawFixed in the code below it also runs as normal, so the problem is definitely with drawing the strings in the combobox (I'm drawing the strings to change the colour of them). Anyways, completely stumped as to how to fix this, any help would be appreciated.
Code is below:
-My clear method
Public Sub ClearCombos()
'Clear Applicant Combos
cboPrimary.Items.Clear() 'crashes when it hits this line
cboJoin1.Items.Clear()
cboJoin2.Items.Clear()
cboJoin3.Items.Clear()
cboJoin4.Items.Clear()
End Sub
Drawing the strings in the comboboxes
Sub CheckForAgeOverage()
c_applicants = {cboPrimary, cboJoin1, cboJoin2, cboJoin3, cboJoin4}
Dim curdate As Date = Date.Now
Dim age As Integer
counter = 0
'Check age of applicants
For Each cbo As ComboBox In c_applicants
If CKeyValuePair.GetComboBoxSelectedKey(c_applicants(counter), True) = instApplicant.applicantId Then
age = Math.Floor(DateDiff(DateInterval.Month, DateValue(instApplicant.BirthDate), curdate) / 12)
If age >= 70 Then
overArray.Add(CKeyValuePair.GetComboBoxSelectedValue(c_applicants(counter)))
End If
cbo.DrawMode = DrawMode.OwnerDrawFixed
Else
For Each j As JoinsBU In instJoins
If CKeyValuePair.GetComboBoxSelectedKey(c_applicants(counter), True) = j.Applicant.applicantId Then
age = Math.Floor(DateDiff(DateInterval.Month, DateValue(j.Applicant.BirthDate), curdate) / 12)
If age >= 70 Then
overArray.Add(CKeyValuePair.GetComboBoxSelectedValue(c_applicants(counter)))
End If
cbo.DrawMode = DrawMode.OwnerDrawFixed
End If
Next
End If
counter += 1
Next
End Sub
The Comboboxes DrawItem event:
Private Sub cbo_DrawItem(sender As System.Object, e As System.Windows.Forms.DrawItemEventArgs) Handles cboPrimary.DrawItem, cboJoin1.DrawItem, cboJoin2.DrawItem, cboJoin3.DrawItem, cboJoin4.DrawItem
Dim brush As Brush = Brushes.Black
Dim text As String = (CType(sender, ComboBox)).Items(e.Index).ToString()
counter = 0
For Each s As String In overArray
If text = overArray(counter) Then
brush = Brushes.Red
Else
brush = Brushes.Black
End If
counter += 1
Next
e.Graphics.DrawString(sender.Items(e.Index).ToString(), e.Font, brush, _
e.Bounds, StringFormat.GenericDefault)
counter = 0
End Sub
It looks like this shouldn't happen, but it obviously is. The actual error might be in this line in the DrawItem handler:
Dim text As String = (CType(sender, ComboBox)).Items(e.Index).ToString()
Try separating the assignment out of the Dim statement, and check the value of e.Index to make sure it is non-negative. If that's the problem, you could probably work around it with an if to make sure e.Index is non-negative.

DataGridView not Refreshing/Updating/Reloading Data. After Child form closes

This is a VB.NET, Winforms App. I have a datagridview on "Form1" that uses a databinding.datasource which is an Entity Framework table. I fill the datagridview with the below function on Form1:
Sub PM_UnitViewGrid()
Try
_form1.UnitsBindingSource.DataSource = db.units.Where(Function(f) f.propertyId = _form1.CurrentPropertyId).OrderBy(Function(F) F.unitNumber)
_form1.UnitDataGridView.DataSource = _form1.UnitsBindingSource.DataSource
Dim iCount As Integer = _form1.UnitDataGridView.RowCount
For x As Integer = 0 To iCount - 1
If Not IsNothing(_form1.UnitDataGridView.Rows(x).Cells(4).Value) Then
Dim tid As Integer = _form1.UnitDataGridView.Rows(x).Cells(4).Value
Dim _ten As tenant = db.tenants.Single(Function(f) f.Occupantid = tid)
_form1.UnitDataGridView.Rows(x).Cells(1).Value = _ten.first_name + ", " + _ten.last_name
Else
Dim btnColumn As DataGridViewButtonCell = CType(_form1.UnitDataGridView.Rows(x).Cells(1), DataGridViewButtonCell)
btnColumn.Style.BackColor = Color.Green
_form1.UnitDataGridView.Rows(x).Cells(1).Value = "VACANT"
End If
Next
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Return
End Sub
This works great and also assigns the needed values to an unbound column. The problem is that the cells(1) is a button. Which when clicked takes the user to another form as a new dialog window. The function for which is below. However, once the changes are made in that form I need for the datagridview to refresh the data that its using from the database and show the correct data. As it stands right now the values are not updating on the datagridview unless the app is completely exited and restarted. Nothing I have found seems to work and Refresh and Update only redraw the control. I need the underlying datasource to refresh and then the datagridview once the child form is exited.. This has had me stumped for a good 36 hours now and I am lost as to why nothing I am trying is working. ANY and all help would be greatly appreciated.
The sub that loads the child form based on the cells(1) button clicked is as follows:
Private Sub UnitDataGridView_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles UnitDataGridView.CellContentClick
UnitDataGridView.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)
Dim y As DataGridViewCellEventArgs = e
Dim Tid As Integer = Nothing
If e.ColumnIndex = 1 Then
If Not e.RowIndex = -1 Then
If Not IsNothing(UnitDataGridView.Rows(e.RowIndex).Cells(4).Value) Then
currentTenent = UnitDataGridView.Rows(e.RowIndex).Cells(4).Value
TenentIdentification = currentTenent
If Not IsNothing(e) Then
If Not IsNothing(UnitDataGridView.Rows(e.RowIndex).Cells(4).Value) Then
Tid = UnitDataGridView.Rows(e.RowIndex).Cells(4).Value
Dim _ten As tenant = db.tenants.Single(Function(f) f.Occupantid = Tid) 'tenant is a table entity
TenantViewSubs.tenId = _ten.Occupantid
Dim t As New TenantView
t.tenId = tid
t.ShowDialog()
End If
End If
PropertyManagSubs.PM_UnitViewGrid() 'This is the function that is above that fills the datagridview
Else
Dim uTview As New UnassignedTenants
uTview.selectedProperty = selectedProperty 'selectedProperty is Integer
uTview.ShowDialog()
PropertyManagSubs.PM_UnitViewGrid() 'This is the function that is above that fills the datagridview
End If
End If
End If
End Sub
I tried each of the following code blocks after the t.ShowDialog() line with no change at all.
UnitDataGridView.Refresh()
.
UnitsBindingSource.Dispose()
UnitsBindingSource.DataSource = db.units.Where(Function(f) f.propertyId = selectedProperty).OrderBy(Function(f) f.unitNumber)
UnitDataGridView.DataSource = UnitsBindingSource.DataSource
.
UnitsBindingSource.DataSource = nothing
unitsBindingSource.DataSource = db.units.Where(Function(f) f.propertyId = selectedProperty).OrderBy(Function(f) f.unitNumber)
UnitDataGridView.DataSource = UnitsBindingSource.DataSource
I finally fixed this on my own.. It was in the way I passed my db context to the databinding..
I simply wrote the below sub:
Private Sub UpdateValues()
Dim context As New storageEntities 'storageEntities is an Entity
Dim query = context.units.Where(Function(F) F.propertyId = selectedProperty).OrderBy(Function(f) f.unitNumber)
UnitDataGridView.DataSource = query
End Sub
Then anytime a child form updated data I simply call
UpdateValues()
After the dialog box closes.
This may help someone else with the same problems so that is why I am posting it.