Variable value lost within 2 classes - vb.net

I have tried the autocomplete code from here :
Need a VB.net Combobox derived class for pattern matched or contains autocomplete functionality
I added some code and I really don't understand why the NbrName is lost.
I added :
Case Keys.Enter
Text = _suggLb.Text
[Select](0, Text.Length)
_suggLb.Visible = False
'Mika
Dim myObject As Form1 = New Form1()
myObject.SearchByName(Text)
'Mika
Return
and this :
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
'Mika Dim testbox As New AutoCompleteComboBox.SuggestComboBox
Me.Controls.Add(testbox)
testbox.DataSource = New List(Of String) From {"Janean Mcgaha", "Tama Gaitan", "Jacque Tinnin", "Elvira Woolfolk", "Fransisca Owens", "Minnie Ardoin",
"Renay Bentler", "Joye Boyter", "Jaime Flannery", "Maryland Arai", "Walton Edelstein", "Nereida Storrs",
"Theron Zinn", "Katharyn Estrella", "Alline Dubin", "Edra Bhatti", "Willa Jeppson", "Chelsea Revel",
"Sonya Lowy", "Danelle Kapoor"}
NbrName = 20
End Sub
Public Sub SearchByName(text As String)
Dim StrTmp As String
StrTmp = text + NbrName.ToString
End Sub
and unfortunately, the variable NbrName remains to 0.
Here under the whole code.
Can someone explain me where is the problem ?
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Linq
Imports System.Linq.Expressions
Imports System.Windows.Forms
Public Class Form1
Dim testbox As New AutoCompleteComboBox.SuggestComboBox
Public NbrName As Integer
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
'Mika Dim testbox As New AutoCompleteComboBox.SuggestComboBox
Me.Controls.Add(testbox)
testbox.DataSource = New List(Of String) From {"Janean Mcgaha", "Tama Gaitan", "Jacque Tinnin", "Elvira Woolfolk", "Fransisca Owens", "Minnie Ardoin",
"Renay Bentler", "Joye Boyter", "Jaime Flannery", "Maryland Arai", "Walton Edelstein", "Nereida Storrs",
"Theron Zinn", "Katharyn Estrella", "Alline Dubin", "Edra Bhatti", "Willa Jeppson", "Chelsea Revel",
"Sonya Lowy", "Danelle Kapoor"}
NbrName = 20
End Sub
Public Sub SearchByName(text As String)
Dim StrTmp As String
StrTmp = text + NbrName.ToString
End Sub
End Class
Namespace AutoCompleteComboBox
Public Class SuggestComboBox
Inherits ComboBox
#Region "fields and properties"
Private ReadOnly _suggLb As New ListBox() With {.Visible = False, .TabStop = False}
Private ReadOnly _suggBindingList As New BindingList(Of String)()
Private _propertySelector As Expression(Of Func(Of ObjectCollection, IEnumerable(Of String)))
Private _propertySelectorCompiled As Func(Of ObjectCollection, IEnumerable(Of String))
Private _filterRule As Expression(Of Func(Of String, String, Boolean))
Private _filterRuleCompiled As Func(Of String, Boolean)
Private _suggestListOrderRule As Expression(Of Func(Of String, String))
Private _suggestListOrderRuleCompiled As Func(Of String, String)
Public Property SuggestBoxHeight() As Integer
Get
Return _suggLb.Height
End Get
Set(value As Integer)
If value > 0 Then
_suggLb.Height = value
End If
End Set
End Property
''' <summary>
''' If the item-type of the ComboBox is not string,
''' you can set here which property should be used
''' </summary>
Public Property PropertySelector() As Expression(Of Func(Of ObjectCollection, IEnumerable(Of String)))
Get
Return _propertySelector
End Get
Set(value As Expression(Of Func(Of ObjectCollection, IEnumerable(Of String))))
If value Is Nothing Then
Return
End If
_propertySelector = value
_propertySelectorCompiled = value.Compile()
End Set
End Property
'''<summary>
''' Lambda-Expression to determine the suggested items
''' (as Expression here because simple lamda (func) is not serializable)
''' <para>default: case-insensitive contains search</para>
''' <para>1st string: list item</para>
''' <para>2nd string: typed text</para>
'''</summary>
Public Property FilterRule() As Expression(Of Func(Of String, String, Boolean))
Get
Return _filterRule
End Get
Set(value As Expression(Of Func(Of String, String, Boolean)))
If value Is Nothing Then
Return
End If
_filterRule = value
_filterRuleCompiled = Function(item) value.Compile()(item, Text)
End Set
End Property
'''<summary>
''' Lambda-Expression to order the suggested items
''' (as Expression here because simple lamda (func) is not serializable)
''' <para>default: alphabetic ordering</para>
'''</summary>
Public Property SuggestListOrderRule() As Expression(Of Func(Of String, String))
Get
Return _suggestListOrderRule
End Get
Set(value As Expression(Of Func(Of String, String)))
If value Is Nothing Then
Return
End If
_suggestListOrderRule = value
_suggestListOrderRuleCompiled = value.Compile()
End Set
End Property
#End Region
''' <summary>
''' ctor
''' </summary>
Public Sub New()
' set the standard rules:
_filterRuleCompiled = Function(s) s.ToLower().Contains(Text.Trim().ToLower())
_suggestListOrderRuleCompiled = Function(s) s
_propertySelectorCompiled = Function(collection) collection.Cast(Of String)()
_suggLb.DataSource = _suggBindingList
AddHandler _suggLb.Click, AddressOf SuggLbOnClick
AddHandler ParentChanged, AddressOf OnParentChanged
End Sub
''' <summary>
''' the magic happens here ;-)
''' </summary>
''' <param name="e"></param>
Protected Overrides Sub OnTextChanged(e As EventArgs)
MyBase.OnTextChanged(e)
If Not Focused Then
Return
End If
_suggBindingList.Clear()
_suggBindingList.RaiseListChangedEvents = False
_propertySelectorCompiled(Items).Where(_filterRuleCompiled).OrderBy(_suggestListOrderRuleCompiled).ToList().ForEach(AddressOf _suggBindingList.Add)
_suggBindingList.RaiseListChangedEvents = True
_suggBindingList.ResetBindings()
_suggLb.Visible = _suggBindingList.Any()
If _suggBindingList.Count = 1 AndAlso _suggBindingList.[Single]().Length = Text.Trim().Length Then
Text = _suggBindingList.[Single]()
[Select](0, Text.Length)
_suggLb.Visible = False
End If
End Sub
#Region "size and position of suggest box"
''' <summary>
''' suggest-ListBox is added to parent control
''' (in ctor parent isn't already assigned)
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Private Overloads Sub OnParentChanged(sender As Object, e As EventArgs)
Parent.Controls.Add(_suggLb)
Parent.Controls.SetChildIndex(_suggLb, 0)
_suggLb.Top = Top + Height - 3
_suggLb.Left = Left + 3
_suggLb.Width = Width - 20
_suggLb.Font = New Font("Segoe UI", 9)
End Sub
Protected Overrides Sub OnLocationChanged(e As EventArgs)
MyBase.OnLocationChanged(e)
_suggLb.Top = Top + Height - 3
_suggLb.Left = Left + 3
End Sub
Protected Overrides Sub OnSizeChanged(e As EventArgs)
MyBase.OnSizeChanged(e)
_suggLb.Width = Width - 20
End Sub
#End Region
#Region "visibility of suggest box"
Protected Overrides Sub OnLostFocus(e As EventArgs)
' _suggLb can only getting focused by clicking (because TabStop is off)
' --> click-eventhandler 'SuggLbOnClick' is called
If Not _suggLb.Focused Then
HideSuggBox()
End If
MyBase.OnLostFocus(e)
End Sub
Private Sub SuggLbOnClick(sender As Object, eventArgs As EventArgs)
Text = _suggLb.Text
Focus()
End Sub
Private Sub HideSuggBox()
_suggLb.Visible = False
End Sub
Protected Overrides Sub OnDropDown(e As EventArgs)
HideSuggBox()
MyBase.OnDropDown(e)
End Sub
#End Region
#Region "keystroke events"
''' <summary>
''' if the suggest-ListBox is visible some keystrokes
''' should behave in a custom way
''' </summary>
''' <param name="e"></param>
Protected Overrides Sub OnPreviewKeyDown(e As PreviewKeyDownEventArgs)
If Not _suggLb.Visible Then
MyBase.OnPreviewKeyDown(e)
Return
End If
Select Case e.KeyCode
Case Keys.Down
If _suggLb.SelectedIndex < _suggBindingList.Count - 1 Then
_suggLb.SelectedIndex += 1
End If
Return
Case Keys.Up
If _suggLb.SelectedIndex > 0 Then
_suggLb.SelectedIndex -= 1
End If
Return
Case Keys.Enter
Text = _suggLb.Text
[Select](0, Text.Length)
_suggLb.Visible = False
'Mika
Dim myObject As Form1 = New Form1()
myObject.SearchByName(Text)
'Mika
Return
Case Keys.Escape
HideSuggBox()
Return
End Select
MyBase.OnPreviewKeyDown(e)
End Sub
Private Shared ReadOnly KeysToHandle As List(Of Keys) = New List(Of Keys) From {Keys.Down, Keys.Up, Keys.Enter, Keys.Escape}
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
' the keysstrokes of our interest should not be processed be base class:
If _suggLb.Visible AndAlso KeysToHandle.Contains(keyData) Then
Return True
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
#End Region
End Class
End Namespace

Related

DataGridView ComboBox column that will accept any text - Dropdown populated by Column

https://stackoverflow.com/a/59545459/20359642
Hi, on the article above, I grabbed the code snippet from Sidupac. This class works but it has a different drop down list for each row. I want each row to be populated with the same list. I am not very good at classes, can someone please help? My goal is to be able to add a column to a DataGridView that will act as a combobox but also accepts manual text input as well.
Public Class DataGridViewDropDownComboBoxColumn
Inherits DataGridViewColumn
Public Sub New()
MyBase.New(New DataGridViewDropDownComboBoxCell)
End Sub
Public Property DropDownStyle As ComboBoxStyle
Public Property DataSource As Object
Public Property ValueMember As Object
Public Property DisplayMember As Object
Public Overrides Property CellTemplate As DataGridViewCell
Get
Return MyBase.CellTemplate
End Get
Set
' Ensure that the cell used for the template is a DataGridViewDropDownComboBoxCell.
If ((Not (Value) Is Nothing) AndAlso Not Value.GetType.IsAssignableFrom(GetType(DataGridViewDropDownComboBoxCell))) Then
Throw New InvalidCastException("Must be a DropDownCell")
End If
MyBase.CellTemplate = Value
End Set
End Property
End Class
Public Class DataGridViewDropDownComboBoxCell
Inherits DataGridViewTextBoxCell
Public Sub New()
MyBase.New
End Sub
Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, ByVal initialFormattedValue As Object, ByVal dataGridViewCellStyle As DataGridViewCellStyle)
' Set the value of the editing control to the current cell value.
MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle)
Dim ctl As DataGridViewDropDownComboBoxEditingControl = CType(DataGridView.EditingControl, DataGridViewDropDownComboBoxEditingControl)
' Use the default row value when Value property is null.
If (Me.Value Is Nothing) Or IsDBNull(Me.Value) Then
ctl.Text = CType(Me.DefaultNewRowValue, String)
Else
ctl.Text = CType(Me.Value, String)
End If
'ctl.BringToFront()
'ctl.Focus()
'ctl.DroppedDown = True
End Sub
Public Overrides ReadOnly Property EditType As Type
Get
' Return the type of the editing control that DataGridViewDropDownComboBoxCell uses.
Return GetType(DataGridViewDropDownComboBoxEditingControl)
End Get
End Property
Public Overrides ReadOnly Property ValueType As Type
Get
' Return the type of the value that DataGridViewDropDownComboBoxCell contains.
Return GetType(String)
End Get
End Property
Public Overrides ReadOnly Property DefaultNewRowValue As Object
Get
' Use the current date and time as the default value.
Return ""
End Get
End Property
End Class
Class DataGridViewDropDownComboBoxEditingControl
Inherits ComboBox
Implements IDataGridViewEditingControl
Private dataGridView As DataGridView
Private valueChanged As Boolean = False
Private rowIndex As Integer
Public Sub New()
MyBase.New
End Sub
Public Shadows Property DropDownStyle() As ComboBoxStyle
Get
Return MyBase.DropDownStyle
End Get
Set(ByVal value As ComboBoxStyle)
If value = ComboBoxStyle.Simple Then
'Throw New NotSupportedException("ComboBoxStyle.Simple not supported")
value = ComboBoxStyle.DropDown
End If
MyBase.DropDownStyle = value
End Set
End Property
' Implements the IDataGridViewEditingControl.EditingControlFormattedValue
' property.
Public Property EditingControlFormattedValue As Object Implements IDataGridViewEditingControl.EditingControlFormattedValue
Get
Return Me.Text
End Get
Set
If (TypeOf Value Is String) Then
Me.Text = CStr(Value)
End If
End Set
End Property
' Implements the
' IDataGridViewEditingControl.GetEditingControlFormattedValue method.
Public Function GetEditingControlFormattedValue(ByVal context As DataGridViewDataErrorContexts) As Object Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
Return Me.EditingControlFormattedValue
End Function
' Implements the
' IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.
Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As DataGridViewCellStyle) Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl
Me.Font = dataGridViewCellStyle.Font
Me.ForeColor = dataGridViewCellStyle.ForeColor
Me.BackColor = dataGridViewCellStyle.BackColor
End Sub
' Implements the IDataGridViewEditingControl.EditingControlRowIndex
' property.
Public Property EditingControlRowIndex As Integer Implements IDataGridViewEditingControl.EditingControlRowIndex
Get
Return Me.rowIndex
End Get
Set
Me.rowIndex = Value
End Set
End Property
' Implements the IDataGridViewEditingControl.EditingControlWantsInputKey
' method.
Public Function EditingControlWantsInputKey(ByVal key As Keys, ByVal dataGridViewWantsInputKey As Boolean) As Boolean Implements IDataGridViewEditingControl.EditingControlWantsInputKey
' Let the DateTimePicker handle the keys listed.
Select Case ((key And Keys.KeyCode))
Case Keys.Left, Keys.Up, Keys.Down, Keys.Right, Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp, Keys.F4
Return True
Case Else
Return Not dataGridViewWantsInputKey
End Select
End Function
' Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit
' method.
Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
Dim col As DataGridViewDropDownComboBoxColumn = CType(dataGridView.Columns(dataGridView.CurrentCell.ColumnIndex), DataGridViewDropDownComboBoxColumn)
If (col Is Nothing) Then
Throw New InvalidCastException("Must be in a DropDownComboBoxColumn")
End If
DropDownStyle = col.DropDownStyle
Items.Clear()
If IsDBNull(dataGridView.CurrentCell.Value) Then
Text = ""
Else
Text = CType(dataGridView.CurrentCell.Value, String)
End If
Items.Add(Text)
Dim dt As DataTable = New DataTable
Dim ct As Integer = 0, cx As Integer = 0
Try
dt = DirectCast(col.DataSource, DataTable)
If Not col.DisplayMember Is Nothing Then
For Each c As DataColumn In dt.Columns
If c.ColumnName Is col.DisplayMember Then
cx = ct
End If
ct += 1
Next
End If
For Each r As DataRow In dt.Rows
If Not col.DisplayMember Is Nothing Then
If Not Items.Contains(r(cx)) Then Items.Add(r(cx))
Else
If dt.Columns.Count = 1 Then
If Not Items.Contains(r(0)) Then Items.Add(r(0))
Else
If Not Items.Contains(r(dt.Columns.Count - 1)) Then Items.Add(r(dt.Columns.Count - 1))
End If
End If
Next
Catch ex As Exception
End Try
'DropDownStyle = col.DropDownStyle
'ValueMember = col.ValueMember
'DisplayMember = col.DisplayMember
'DataSource = col.DataSource
' (If you don't explicitly set the Text then the current value is
' always replaced with one from the drop-down list when edit begins.)
'If IsDBNull(dataGridView.CurrentCell.Value) Then
' Text = ""
'Else
' Text = CType(dataGridView.CurrentCell.Value, String)
'End If
End Sub
' Implements the IDataGridViewEditingControl
' .RepositionEditingControlOnValueChange property.
Public ReadOnly Property RepositionEditingControlOnValueChange As Boolean Implements IDataGridViewEditingControl.RepositionEditingControlOnValueChange
Get
Return False
End Get
End Property
' Implements the IDataGridViewEditingControl
' .EditingControlDataGridView property.
Public Property EditingControlDataGridView As DataGridView Implements IDataGridViewEditingControl.EditingControlDataGridView
Get
Return Me.dataGridView
End Get
Set
Me.dataGridView = Value
End Set
End Property
' Implements the IDataGridViewEditingControl
' .EditingControlValueChanged property.
Public Property EditingControlValueChanged As Boolean Implements IDataGridViewEditingControl.EditingControlValueChanged
Get
Return Me.valueChanged
End Get
Set
Me.valueChanged = Value
End Set
End Property
' Implements the IDataGridViewEditingControl
' .EditingPanelCursor property.
Public ReadOnly Property EditingPanelCursor As Cursor Implements IDataGridViewEditingControl.EditingPanelCursor
Get
Return MyBase.Cursor
End Get
End Property
Protected Overrides Sub OnTextChanged(ByVal eventargs As EventArgs)
' Notify the DataGridView that the contents of the cell
' have changed.
Me.valueChanged = True
Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
MyBase.OnTextChanged(eventargs)
End Sub
Protected Overrides Sub OnSelectedIndexChanged(ByVal e As EventArgs)
' Notify the DataGridView that the contents of the cell
' have changed.
Me.valueChanged = True
Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
MyBase.OnSelectedIndexChanged(e)
End Sub
End Class
I've tried messing around with the class myself but I just cant seem to figure it out.
I actually figured it out. The DataSource was not populating the dropdowns because I was not giving it a DataTable to reference. I was giving it a string array. I just need to alter the class a bit to handle different types of inputs for the DataSource.
For example, I changed the code inside of the try statement in the PrepareEditingControlForEdit procedure to the code below:
If TypeOf col.DataSource Is String Then
Items.Add(col.DataSource)
ElseIf TypeOf col.DataSource Is String() Then
For Each obj As Object In DirectCast(col.DataSource, String())
Items.Add(obj)
Next
ElseIf TypeOf col.DataSource Is List(Of String) Then
For Each obj As String In DirectCast(col.DataSource, List(Of String))
Items.Add(obj)
Next
ElseIf TypeOf col.DataSource Is List(Of Object) Then
For Each obj As String In DirectCast(col.DataSource, List(Of Object))
Items.Add(obj)
Next
ElseIf TypeOf col.DataSource Is DataTable Then
dt = DirectCast(col.DataSource, DataTable)
If Not col.DisplayMember Is Nothing Then
For Each c As DataColumn In dt.Columns
If c.ColumnName Is col.DisplayMember Then
cx = ct
End If
ct += 1
Next
End If
For Each r As DataRow In dt.Rows
If Not col.DisplayMember Is Nothing Then
If Not Items.Contains(r(cx)) Then Items.Add(r(cx))
Else
If dt.Columns.Count = 1 Then
If Not Items.Contains(r(0)) Then Items.Add(r(0))
Else
If Not Items.Contains(r(dt.Columns.Count - 1)) Then Items.Add(r(dt.Columns.Count - 1))
End If
End If
Next
End If

Returning object instead of string and integer

I'm working on a vb.net project where a user can save and open a binary text.
However, the problem is that the when opening a file, it returns a object instead of string and integer.
It returns Projectname.Classname
What I want it to return is name and age that the user entered when saving the file.
Here is my code:
''' <summary>
''' When the user clicks open
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub OpenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OpenToolStripMenuItem.Click
Try
If (openFileDialog1.ShowDialog = DialogResult.OK) Then
thefilename = openFileDialog1.FileName
Dim message = animalmgr.ReadFile(thefilename)
'Getting method from manager
If (Not (message) Is Nothing) Then
message.ToList().ForEach(Sub(msg) Resultlst.Items.Add(msg))
Else
UpdateResults()
End If
End If
Catch ex As Exception
MessageBox.Show(ex.ToString, "Error in opening file")
End Try
End Sub
ReadFile function in the manager class:
''' <summary>
''' Reads a file from binary
''' </summary>
''' <param name="filename"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Function ReadFile(ByVal filename As String) As Animal()
Dim BinSerial As BinSerializerUtility = New BinSerializerUtility
Dim animals = BinSerial.BinaryFileDeSerialize(Of Animal)(filename)
Return animals.ToArray
End Function
I did the exact same project in C# which worked perfectly, I don't know why it doesn't work in vb.net however. Does anyone know the problem and how to solve it?
Update:
Class BinSerializerUtility
Public Class BinSerializerUtility
Public Sub BinaryFileSerialize(ByVal objs As List(Of Animal), ByVal filePath As String)
Dim fileStream As FileStream = Nothing
Try
fileStream = New FileStream(filePath, FileMode.Create)
Dim b As BinaryFormatter = New BinaryFormatter
For Each obj In objs
b.Serialize(fileStream, obj)
Next
Finally
If (Not (fileStream) Is Nothing) Then
fileStream.Close()
End If
End Try
End Sub
Public Function BinaryFileDeSerialize(Of T As {Class})(ByVal filePath As String) As List(Of T)
Dim list = New List(Of T)
If Not File.Exists(filePath) Then
Throw New FileNotFoundException(("The file" + " was not found. "), filePath)
End If
Dim fileStream = New FileStream(filePath, FileMode.Open)
Dim b As BinaryFormatter = New BinaryFormatter
While (fileStream.Position < fileStream.Length)
list.Add(CType(b.Deserialize(fileStream), T))
End While
Return list
End Function
End Class
Animal class:
<Serializable()>
Public MustInherit Class Animal
Implements IAnimal
Private theCatagorytype As Categorytype
Private m_name As String
Private m_age As Integer
Private m_gender As String
Private m_id As Integer
Public Sub New(ByVal typ As Categorytype)
MyBase.New()
theCatagorytype = typ
End Sub
Public Sub New()
MyBase.New()
End Sub
#Region "Properties"
Public Overridable ReadOnly Property Description As String
Get
Return String.Format("{0}, {1}, {2}, {3}", Me.Id, Me.Name, Me.Age, Me.Gender)
End Get
End Property
Public Property Categorytype As Categorytype
Get
Return theCatagorytype
End Get
Set(value As Categorytype)
theCatagorytype = value
End Set
End Property
Public Property Id As Integer Implements IAnimal.Id
Get
Return m_id
End Get
Set(value As Integer)
If (value > 0) Then
m_id = value
End If
End Set
End Property
Public Property Name As String Implements IAnimal.Name
Get
Return m_name
End Get
Set(value As String)
m_name = value
End Set
End Property
Public Property Age As Integer
Get
Return m_age
End Get
Set(value As Integer)
m_age = value
End Set
End Property
Public Property Gender As String Implements IAnimal.Gender
Get
Return m_gender
End Get
Set(value As String)
m_gender = value
End Set
End Property
#End Region
Public MustOverride Function GetEaterType() As EaterType Implements IAnimal.GetEaterType
Public MustOverride Function GetSpecies() As String Implements IAnimal.GetSpecies
End Class
Rather than writing a class wrapper for an operation, I think it makes more sense to put such Save and Load functions in the class itself:
' in Animal class:
Friend Shared Function LoadData(myFile As String) As List(Of Animal)
Dim newList As List(Of Animal)
If File.Exists(myFile) Then
Using fs As New FileStream(myFile, FileMode.Open)
Dim bf = New BinaryFormatter
newList = CType(bf.Deserialize(fs), List(Of Animal))
End Using
Else
'return empty list of there is no file
newList = New List(Of Animal)
End If
Return newList
End Function
This seems simpler than trying to read one object at a time and place it in a List. Organizationally, it makes for fewer utility classes if the Foos, Bars and Animals can all serialize and deserialize themselves. To load them:
animals = Animal.LoadData(FileName)
' put animals in a ListBox:
myfrm.ListBox1.Items.AddRange(animals.ToArray)
Even better than making a copy of the animals for the list box, is to use your List(Of Animal) as the DataSource. That way, the user sees the same data set as your code is using.
When adding objects to a listbox or dropdown list, by default it uses ToString() to give you a string representation of the object, and the class name is the default ToString() implementation.
If you override ToString() in your Animal class, it will display however you need it to.
EDIT This is assuming you really want your ReadFile method to return a collection of Animal objects, and you want to add the actual objects to the listbox instead of truly adding string representations to the listbox.

Click messagebox from code

Alright so, don't ask why, PLEASE, but i really need this.
So, i'll display a MessageBox to the user for 2 seconds then i need to close it automatically, without the user input.
Messagebox.Show("RandomStringHere")
System.Threading.Thread.Sleep("2000")
And here i got stuck. Is there any way possible i can do this? And please don't ask why, but it is indeed necessary.
I couldn't find any help on the internet with this problem i have so i guess you guys can help me.
Just create your own form. You can do this in the designer or using code as in the example below. Set a timer and close the form in two seconds:
Private _msgForm As Form
Private _tmr As Windows.Forms.Timer
Private Sub Button9_Click(sender As Object, e As EventArgs) Handles Button9.Click
_msgForm = New Form
With _msgForm
.Height = 200
.Width = 300
.StartPosition = FormStartPosition.CenterScreen
.Text = "Message"
End With
Dim btn As New Button
With btn
.Text = "OK"
.Top = _msgForm.Height - 75
.Left = _msgForm.Width - 100
.Anchor = AnchorStyles.Right Or AnchorStyles.Bottom
End With
_msgForm.Controls.Add(btn)
Dim lbl As New Label
With lbl
.Text = "This is the text of the message box"
.Left = 0
.Top = 0
.Width = _msgForm.ClientSize.Width
.Height = _msgForm.ClientSize.Height - 120
.Anchor = AnchorStyles.Bottom Or AnchorStyles.Left Or AnchorStyles.Right Or AnchorStyles.Top
End With
_msgForm.Controls.Add(lbl)
_tmr = New Windows.Forms.Timer
With _tmr
.Interval = 2000
.Enabled = True
End With
AddHandler _tmr.Tick, AddressOf TimerTick
AddHandler btn.Click, AddressOf ButtonClick
_msgForm.ShowDialog()
End Sub
Private Sub TimerTick(sender As Object, e As EventArgs)
_msgForm.Close()
End Sub
Private Sub ButtonClick(sender As Object, e As EventArgs)
CType(sender, Button).FindForm.Close()
End Sub
Example usage:
Using New CenteredMessageBox(Owner:=Me,
TextFont:=Me.Font,
TimeOut:=2500)
MessageBox.Show("Test Text",
"Test Title",
MessageBoxButtons.OK,
MessageBoxIcon.Information)
End Using
The Custom MessageBox:
' [ Centered MessageBox ]
' By Elektro
'
' The author of the original idea is Hans Passant:
' http://stackoverflow.com/questions/2576156/winforms-how-can-i-make-messagebox-appear-centered-on-mainform
'
' Examples :
'
'Using New CenteredMessageBox(Owner:=Me,
' TextFont:=New Font("Lucida Console", Font.SizeInPoints, FontStyle.Bold),
' TimeOut:=2500)
'
' MessageBox.Show("Test Text", "Test Title", MessageBoxButtons.OK, MessageBoxIcon.Information)
'
'End Using
#Region " Centered MessageBox Class"
#Region " Imports "
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Windows.Forms
#End Region
Class CenteredMessageBox : Implements IDisposable
#Region " Variables, Objects, Properties "
Private mTries As Integer = 0
Private mOwner As Form
Private mFont As Font
Private mTimeOut As Integer
Private WithEvents TimeoutTimer As Timer
Private ReadOnly Property MessageBoxWindowHandle As IntPtr
Get
Return _MessageBoxWindowHandle
End Get
End Property
Dim _MessageBoxWindowHandle As IntPtr = IntPtr.Zero
#End Region
#Region " P/Invoke "
Friend Class NativeMethods
Friend Const WM_SETFONT As Integer = &H30
Friend Const WM_GETFONT As Integer = &H31
Friend Delegate Function EnumThreadWndProc(hWnd As IntPtr, lp As IntPtr) As Boolean
Friend Declare Function SetWindowPos Lib "user32" (ByVal hwnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal wFlags As UInt32) As Boolean
<DllImport("user32.dll")>
Friend Shared Function EnumThreadWindows(tid As Integer, callback As NativeMethods.EnumThreadWndProc, lp As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll")>
Friend Shared Function GetCurrentThreadId() As Integer
End Function
<DllImport("user32.dll", CharSet:=CharSet.Unicode)>
Friend Shared Function GetClassName(hWnd As IntPtr, buffer As StringBuilder, buflen As Integer) As Integer
End Function
<DllImport("user32.dll")>
Friend Shared Function GetDlgItem(hWnd As IntPtr, item As Integer) As IntPtr
End Function
<DllImport("user32.dll")>
Friend Shared Function SendMessage(hWnd As IntPtr, msg As Integer, wp As IntPtr, lp As IntPtr) As IntPtr
End Function
<DllImport("user32.dll")>
Friend Shared Function GetWindowRect(hWnd As IntPtr, ByRef rc As RECT) As Boolean
End Function
<DllImport("user32.dll")>
Friend Shared Function MoveWindow(hWnd As IntPtr, x As Integer, y As Integer, w As Integer, h As Integer, repaint As Boolean) As Boolean
End Function
''' <summary>
''' <para>The DestroyWindow function destroys the specified window. The function sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus from it. The function also destroys the window's menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if the window is at the top of the viewer chain).</para>
''' <para>If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window.</para>
''' <para>DestroyWindow also destroys modeless dialog boxes created by the CreateDialog function.</para>
''' </summary>
''' <param name="hwnd">Handle to the window to be destroyed.</param>
''' <returns>If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError.</returns>
<DllImport("user32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
Friend Shared Function DestroyWindow(hwnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
End Class
Structure RECT
Public Left As Integer
Public Top As Integer
Public Right As Integer
Public Bottom As Integer
End Structure
#End Region
#Region " Constructors "
''' <summary>
''' Initializes a new instance of the <see cref="CenteredMessageBox"/> class.
''' </summary>
''' <param name="Owner">Indicates the form that owns this messagebox.</param>
''' <param name="TextFont">Indicates the text-font used to display the text label.</param>
''' <param name="TimeOut">
''' Indicates the timeout, in ms, to auto-close this <see cref="CenteredMessageBox"/>
''' Default is '0' which means Infinite.
''' </param>
Public Sub New(ByVal Owner As Form,
Optional TextFont As Font = Nothing,
Optional TimeOut As Integer = 0I)
mOwner = Owner
mFont = TextFont
mTimeOut = TimeOut
Owner.BeginInvoke(New MethodInvoker(AddressOf findDialog))
End Sub
#End Region
#Region " Private MEthods "
Private Sub findDialog()
' Enumerate windows to find the message box
If mTries < 0 Then
Return
End If
Dim callback As New NativeMethods.EnumThreadWndProc(AddressOf checkWindow)
If NativeMethods.EnumThreadWindows(NativeMethods.GetCurrentThreadId(), callback, IntPtr.Zero) Then
If System.Threading.Interlocked.Increment(mTries) < 10 Then
mOwner.BeginInvoke(New MethodInvoker(AddressOf findDialog))
End If
End If
If mTimeOut > 0 Then
TimeoutTimer = New Timer With {.Interval = mTimeOut, .Enabled = True}
TimeoutTimer.Start()
End If
End Sub
Private Function checkWindow(hWnd As IntPtr, lp As IntPtr) As Boolean
' Checks if <hWnd> is a dialog
Dim sb As New StringBuilder(260)
NativeMethods.GetClassName(hWnd, sb, sb.Capacity)
If sb.ToString() <> "#32770" Then Return True
' Get the STATIC control that displays the text
Dim hText As IntPtr = NativeMethods.GetDlgItem(hWnd, &HFFFF)
Me._MessageBoxWindowHandle = hWnd
Dim frmRect As New Rectangle(mOwner.Location, mOwner.Size)
Dim dlgRect As RECT
NativeMethods.GetWindowRect(hWnd, dlgRect)
If hText <> IntPtr.Zero Then
If mFont Is Nothing Then
' Get the current font
mFont = Font.FromHfont(NativeMethods.SendMessage(hText, NativeMethods.WM_GETFONT, IntPtr.Zero, IntPtr.Zero))
ElseIf mFont IsNot Nothing Then
NativeMethods.SetWindowPos(hText, 0, 70, 35, frmRect.Width, mFont.Height, 0)
End If
NativeMethods.SendMessage(hText, NativeMethods.WM_SETFONT, mFont.ToHfont(), New IntPtr(1))
' Resize and positionate the messagebox window:
NativeMethods.MoveWindow(hWnd,
frmRect.Left + (frmRect.Width - dlgRect.Right + dlgRect.Left) \ 2,
frmRect.Top + (frmRect.Height - dlgRect.Bottom + dlgRect.Top) \ 2,
(dlgRect.Right - dlgRect.Left),
(dlgRect.Bottom - dlgRect.Top), True)
End If
' Done
Return False
End Function
#End Region
#Region " Event Handlers "
Private Sub TimeoutTimer_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles TimeoutTimer.Tick
NativeMethods.DestroyWindow(Me._MessageBoxWindowHandle)
Me.Dispose()
End Sub
#End Region
#Region " IDisposable "
Public Sub Dispose() Implements IDisposable.Dispose
mTries = -1
mOwner = Nothing
If mFont IsNot Nothing Then mFont.Dispose()
End Sub
#End Region
End Class
#End Region

How to center a PictureBox inside a ScrollableControl and then autoscroll on resize

Having a bit of trouble trying to center the view on the center of the element inside a ScrollableControl.
I have no problems centering the control inside the ScrollableControl, however whenever I try to set AutoScrollPosition, the element inside the scroll container docks to the bottom right corner of the innermost container of the ScrollableControl.
Here is the code that I am using (and I am pretty sure the math is correct) :
MyBase.AutoScrollPosition = New System.Drawing.Point(Canvas1.Left - ((MyBase.Width - Canvas1.Size.Width) / 2), Canvas1.Top - ((MyBase.Height - Canvas1.Size.Height) / 2))
The type of project is actually a UserControl, not a Class, so this is not an "inherited" ScrollableControl per se. It is a UserControl type.
What I find most bizzare, is there doesn't appear to be a ScrollToX, only ScrollControlIntoView, and such, which do not do what I wish.
Basically, the end result, is the center of the Viewable area must be the center of the Control contained inside the Scrollable virtual area. I have the Control centered as such, so this is really just a matter of scrolling it into view so the X,Y of the dead center of the inner control, is in the dead center of the viewable area.
Current code for the entire class
Board.vb
Imports System.ComponentModel
Public Class Board
Private _init As Boolean = False
Private _keys As KeyEventArgs = Nothing
''' <summary>
''' </summary>
''' <filterpriority>3</filterpriority>
''' <remarks></remarks>
<Browsable(False), EditorBrowsable(False)> _
Shadows Property BackgroundImage As Image
Get
Return MyBase.BackgroundImage
End Get
Set(value As Image)
MyBase.BackgroundImage = value
End Set
End Property
<Browsable(False), EditorBrowsable(False)> _
Shadows Property AutoScroll As Boolean
Get
Return MyBase.AutoScroll
End Get
Set(value As Boolean)
MyBase.AutoScroll = value
End Set
End Property
<Browsable(False), EditorBrowsable(False)> _
Shadows Property AutoScrollMinSize As System.Drawing.Size
Get
Return MyBase.AutoScrollMinSize
End Get
Set(value As System.Drawing.Size)
MyBase.AutoScrollMinSize = value
End Set
End Property
Public Property Checkerboard As Boolean
Get
Return Canvas1.CheckeredBackground
End Get
Set(value As Boolean)
Canvas1.CheckeredBackground = value
End Set
End Property
Shadows Property BorderStyle As Windows.Forms.BorderStyle
Get
Return Canvas1.BorderStyle
End Get
Set(value As Windows.Forms.BorderStyle)
Canvas1.BorderStyle = value
End Set
End Property
Private Sub Canvas1_MouseEnter(sender As Object, e As EventArgs) Handles Canvas1.MouseEnter
Me.Focus()
End Sub
Public Sub Add(ByVal Image As System.Drawing.Image)
Dim l As New Layer("Layer " & Canvas1.Layers.Count + 1)
l.Graphics.Add(New Graphic(Image, New Point(10, 10)))
Canvas1.Layers.Add(l)
End Sub
Public Property CanvasSize() As System.Drawing.Size
Get
Return Canvas1.Size
End Get
Set(value As System.Drawing.Size)
Canvas1.Size = value
Me.CenterCanvas()
End Set
End Property
Public Property BoardSize() As System.Drawing.Size
Get
Return Me.AutoScrollMinSize
End Get
Set(value As System.Drawing.Size)
Me.AutoScrollMinSize = value
Me.CenterCanvas()
End Set
End Property
Public Function Remove(ByVal Index As Integer) As Boolean
Try
Canvas1.Layers.RemoveAt(Index)
Return True
Catch ex As Exception
Return False
End Try
End Function
Public Sub RefreshCanvas()
Canvas1.Invalidate()
End Sub
Public Sub CenterCanvas()
Canvas1.Location = New System.Drawing.Point((MyBase.DisplayRectangle.Width - Canvas1.Size.Width) / 2, (MyBase.DisplayRectangle.Height - Canvas1.Size.Height) / 2)
'Debug.Print(Canvas1.Top & ", " & Canvas1.Left)
' Dim y As Integer = (Me.Height - Canvas1.Height) / 2
' Dim x As Integer = (Me.Width - Canvas1.Width) / 2
' x = Canvas1.Left - x
' y = Canvas1.Top - y
' Me.AutoScrollPosition = New System.Drawing.Point(x, y)
End Sub
Public Sub New()
' This call is required by the designer.
InitializeComponent()
_init = True
' Add any initialization after the InitializeComponent() call.
Me.CenterCanvas()
End Sub
Private Sub Board_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
_keys = e
End Sub
Private Sub Board_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp
_keys = Nothing
End Sub
Private Sub Board_MouseWheel(sender As Object, e As MouseEventArgs) Handles Me.MouseWheel
Dim l As Layer
l = Canvas1.SelectedLayer
If IsNothing(l) = False Then
Debug.Print("Wheels")
End If
Dim MW As HandledMouseEventArgs = e
MW.Handled = False
End Sub
Private Sub Board_Resize(sender As Object, e As EventArgs) Handles Me.Resize
' If _init Then
' Dim x As Integer = Canvas1.Left - ((MyBase.Width - Canvas1.Size.Width) / 2)
'Dim y As Integer = Canvas1.Top - ((MyBase.Height - Canvas1.Size.Height) / 2)
' MyBase.AutoScrollPosition = New System.Drawing.Point(Canvas1.Left - ((MyBase.Width - Canvas1.Size.Width) / 2), Canvas1.Top - ((MyBase.Height - Canvas1.Size.Height) / 2))
'End If
MyBase.AutoScrollPosition = New System.Drawing.Point( _
Canvas1.Left - MyBase.AutoScrollPosition.X - ((MyBase.ClientSize.Width - Canvas1.Size.Width) \ 2), _
Canvas1.Top - MyBase.AutoScrollPosition.Y - ((MyBase.ClientSize.Height - Canvas1.Size.Height) \ 2))
End Sub
Private Sub Board_SizeChanged(sender As Object, e As EventArgs) Handles Me.SizeChanged
End Sub
End Class
Board.Designer.vb
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Board
Inherits System.Windows.Forms.UserControl
'UserControl1 overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.Canvas1 = New Artisto.Canvas()
CType(Me.Canvas1, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SuspendLayout()
'
'Canvas1
'
Me.Canvas1.Anchor = System.Windows.Forms.AnchorStyles.None
Me.Canvas1.CheckeredBackground = True
Me.Canvas1.Location = New System.Drawing.Point(0, 0)
Me.Canvas1.Name = "Canvas1"
Me.Canvas1.SelectedLayer = Nothing
Me.Canvas1.Size = New System.Drawing.Size(619, 317)
Me.Canvas1.TabIndex = 0
Me.Canvas1.TabStop = False
'
'Board
'
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit
Me.AutoScroll = True
Me.AutoScrollMinSize = New System.Drawing.Size(4096, 2160)
Me.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink
Me.Controls.Add(Me.Canvas1)
Me.DoubleBuffered = True
Me.Name = "Board"
Me.Size = New System.Drawing.Size(1266, 523)
CType(Me.Canvas1, System.ComponentModel.ISupportInitialize).EndInit()
Me.ResumeLayout(False)
End Sub
Friend WithEvents Canvas1 As Artisto.Canvas
End Class

Can't sort BindingSource from the first time on SelectedIndexChange

I have a sub which on SelectedIndexChange - of Customer returns the TransactionBindingSource.
What I want is to show on the databound controls the latest transaction of each selected customer instead of the first one. The weird thing is that when the tab loads (on the 'enter' event I call the selectedIndexChange method and the latest record is selected. However, when I manually select another customer, the first record of each transaction is displayed! This is what I have
Private Sub cboCustomerName_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboCustomerName.SelectedIndexChanged
resetstats()
'Try
Dim iTotalbuyin, iCountBuyins, iSumBuyins, iSumCashouts, iBiggestWin, iBiggestLoss As Integer
Dim oTotalbuyin, oCountBuyIns, oSumCashouts, oBiggestWin, oBiggestLoss As Object
' If Me.cboCustomerName.SelectedIndex <> -1 Then
Dim drv As DataRowView = CType(Me.cboCustomerName.SelectedItem, DataRowView)
Dim SelCustId As Integer = drv.Item("CustomerID")
Me.TransactionTableAdapter.Fill(Me.DbPBDataSet.Transaction, SelCustId)
Me.TransactionBindingSource.Sort = "TransactionID"
Me.TransactionBindingSource.MoveLast()
Any ideas?
You can make your own SortableBindingList class, like so:
Imports System.ComponentModel
Imports System.Reflection
Public Class SortableBindingList(Of T)
Inherits BindingList(Of T)
Private Property IsSorted As Boolean
Private Property SortDirection As ListSortDirection
Private Property SortProperty As PropertyDescriptor
Protected Overrides ReadOnly Property SupportsSortingCore() As Boolean
Get
Return True
End Get
End Property
Protected Overrides ReadOnly Property SortDirectionCore() As ListSortDirection
Get
Return _SortDirection
End Get
End Property
Protected Overloads Overrides ReadOnly Property SortPropertyCore() As PropertyDescriptor
Get
Return _SortProperty
End Get
End Property
Protected Overloads Overrides Sub ApplySortCore(ByVal PDsc As PropertyDescriptor, ByVal Direction As ListSortDirection)
Dim items As List(Of T) = TryCast(Me.Items, List(Of T))
If items Is Nothing Then
IsSorted = False
Else
Dim PCom As New PCompare(Of T)(PDsc.Name, Direction)
items.Sort(PCom)
IsSorted = True
SortDirection = Direction
SortProperty = PDsc
End If
OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))
End Sub
Protected Overloads Overrides ReadOnly Property IsSortedCore() As Boolean
Get
Return _IsSorted
End Get
End Property
Protected Overrides Sub RemoveSortCore()
_IsSorted = False
End Sub
#Region " Constructors "
Sub New(ByVal list As ICollection(Of T))
MyBase.New(CType(list, Global.System.Collections.Generic.IList(Of T)))
End Sub
Sub New()
MyBase.New()
End Sub
#End Region
#Region " Property comparer "
Private Class PCompare(Of T)
Implements IComparer(Of T)
Private Property PropInfo As PropertyInfo
Private Property SortDir As ListSortDirection
Friend Sub New(ByVal SortProperty As String, ByVal SortDirection As ListSortDirection)
SortProperty = CheckPropertyName(SortProperty)
PropInfo = GetType(T).GetProperty(SortProperty)
SortDir = SortDirection
End Sub
''' <summary>
''' Used to change the name of the sorted property for certain classes.
''' </summary>
''' <param name="SortProperty"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function CheckPropertyName(ByVal SortProperty As String) As String
If SortProperty = "BinNumber" AndAlso GetType(T).Name = "BinReportDisplay" Then
Return "BinNumberSort"
End If
Return SortProperty
End Function
Friend Function Compare(ByVal x As T, ByVal y As T) As Integer Implements IComparer(Of T).Compare
Return If(SortDir = ListSortDirection.Ascending, Comparer.[Default].Compare(PropInfo.GetValue(x, Nothing),
PropInfo.GetValue(y, Nothing)), Comparer.[Default].Compare(PropInfo.GetValue(y, Nothing),
PropInfo.GetValue(x, Nothing)))
End Function
End Class
#End Region
End Class
Then sort the list according to how you want it sorted.