inheritance in VB.net - vb.net

Not real sure how to ask this question... Some of my terms may be incorrect but hopefully I'll be able to get the question across. If I have a class something like this
Public Class Agency
public property ID as integer=0
public property Name as string=string.empty
Public sub new()
end sub
end class
and then a factory class that returns a list
Public Class Agency_Controller
Public Sub New()
end sub
Public function Fetch() as list(of Agency)
pop the list and return it
end function
end class
If I create another class say Agency_Misc and want to inherit the Agency Class I get, how to do that?
Public Class Agency_Misc
inherits Agency
public property Address as string=string.empty
end class
Now if I want to use the Agency_Misc, how do I get the Agency_Controller Fetch function? In the code if I were going after the agency... I do something like
Dim oS as list(of Agency)=nothing
dim oC as new Agency_Controller
os=oc.Fetch()
but if I want my list to have the list(of Agency_Misc) (because I was doing some more stuff)
how do I do that. I can't change list(of Agency) to list(of Agency_Misc) because it will tell me it can't convert it I think it was.
Anyway... I'd like to learn what it is I'm missing or what other approach I need to look into.

If you have defined your classes properly, you can do the following:
Define a BaseClass.
Define a DerivedClass which inherits from BaseClass
Define a List(Of BaseClass) and populate it with objects of DerivedClass (the List will accept objects of Dervived class, because these are, through inheritance, also objects of BaseClass.
Access the items in the list with a variable of Type DerivedClass.
What you CAN'T do is populate the list with objects of type BaseClass, and then attempt to access them using a variable of Type DerivedClass.
Ex. #1 THIS will work:
Public Class Form1
Private MyListOfBaseCLass As List(Of MyBaseClass)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MyListOfBaseCLass = New List(Of MyBaseClass)
Dim dc As New MyDerivedCLass("City of Portland", "555 SW 5th Avenue")
MyListOfBaseCLass.Add(dc)
dc = New MyDerivedCLass("City of Salem", "222 E River Road")
MyListOfBaseCLass.Add(dc)
dc = New MyDerivedCLass("City of Denver", "333 SomeStreet")
MyListOfBaseCLass.Add(dc)
End Sub
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each dc As MyDerivedCLass In MyListOfBaseCLass
MsgBox(dc.MyName & ", " & dc.MyAddress)
Next
End Sub
End Class
THIS will FAIL:
Public Class Form1
Private MyListOfBaseCLass As List(Of MyBaseClass)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MyListOfBaseCLass = New List(Of MyBaseClass)
Dim dc As New MyBaseClass("City of Portland")
MyListOfBaseCLass.Add(dc)
dc = New MyBaseClass("City of Salem")
MyListOfBaseCLass.Add(dc)
dc = New MyBaseClass("City of Denver")
MyListOfBaseCLass.Add(dc)
End Sub
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each dc As MyDerivedCLass In MyListOfBaseCLass
MsgBox(dc.MyName & ", " & dc.MyAddress)
Next
End Sub
End Class

You best set the properties in the constructor
Public Class Agency
Private m_ID As Integer
Public Property ID() As Integer
Get
Return m_ID
End Get
Set(ByVal value As Integer)
m_ID = value
End Set
End Property
Private m_name As String
Public Property Name() As String
Get
Return m_name
End Get
Set(ByVal value As String)
m_name = value
End Set
End Property
Sub New(ByVal id As Integer, ByVal name As String)
Me.m_ID = id
Me.m_name = name
End Sub
End Class
...
Dim HiDollar as New Agency(100, "High Dollar")

Related

vb.net Public Shared String loose value when open second form

I'm declaring two strings into my main form this way:
Public Shared SerNum As String = vbNullString
Public Shared SKey As String = vbNullString
Then I give some values to them. After that, I open another form and I try to get values from the two variables but only SerNum preserves his value while SKey turns out to be Nothing.
I repeatedly checked my code but I didn't found a reason for this to happen.
The second form is showed immediatly after giving values.
What can I check to find the error?
At the moment I solved by using a Public Shared Dictionary(of String, String) and putting both strings into it, but I would like to understand where I'm wrong.
EDIT
I found the mistake: SKey was also declared into my sub so the value wasn't assigned to the Public Shared variable but to the local variable.
I thought I had 'commented' that row...
I have a proposition for acceding to your variable from other form :
In From main let's name it "From1" must be like :
Public Class Form1
Public SerNum As String = vbNullString
Public SKey As String = vbNullString
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim fr As New Form2(Me)
SerNum = "ValueNum"
SKey = "ValueKey"
fr.Show()
End Sub
End Class
In your seconde from "Form2" :
Public Class Form2
Dim fr As New Form1
Public Sub New(fr As Form1)
InitializeComponent()
Me.fr = fr
End Sub
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MsgBox(fr.SKey)
MsgBox(fr.SerNum)
End Sub

ListChanged Event not firing?

I have a class with a bindinglist(of T) in it. The bindinglist is bound to a datagridview on my form. When items are added to the bindinglist, they show up in the datagridview however the scrollbar never changes to accommodate for the new data. I am starting to think this is because the Listchanged event isn't being fired (or properly captured by my form). I have my code set up like this:
Data Class:
Public Class data
Implements INotifyPropertyChanged
Public Sub new(byVal att1 as string, ByVal att2 as string)
Attribute1 = att1
Attribute2 = att2
End sub
Private mAttribute1 as string
Public Property Attribute1 as string
Get
return mAttribute1
End get
Set(ByVal value as string)
mAttribute1 = value
OnPropertyChanged("Attribute1")
End Set
End Property
Private mAttribute2 as string
Public Property Attribute2 as string
Get
return mAttribute2
End Get
Set(ByVal value as string)
mAttribute2 = value
OnPropertyChanged("Attribute2")
End Set
End Property
Public Sub OnPropertyChanged(ByVal name As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
End Sub
Public Sub ChangeDataFormat()
'change from one format to the other
End Sub
End Class
Data Generator Class:
Public Class dataGenerator()
private myThread as New System.Theading.Thread(address of StartDataGeneration)
Public Sub new()
mDataList = new bindingList(of Data)
mDataList.RaiseListChangedEvents = True
Private WithEvents mDataList as bindingList(Of Data)
Public readonly DataList as bindingList(of Data)
Get
Return mDataList
End Get
End property
Private Sub StartDataGeneration()
dim att1 as integer = 1
dim att2 as integer = 2
for i as Integer = 0 to 1000
mDataList.Insert(0,New Data(att1.ToString,att2.ToString)
att1 *= 2
att2 *=3
next
End Sub
Public Sub StartDataThread()
myThread.Start()
End Sub
Public Sub ChangeDataFormat()
for each d as data in mDataList
d.ChangeDataFormat()
next
End Sub
End Class
Form:
Public class Form1
Private myGenerators as new BindingList(of dataGenerator)
Private myDataGrids as new BindingList(of DataGridView)
Private Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Mybase.Load
dim NumberOfGenerators as integer = Convert.ToInt32(My.Settings.CraneCount)
for i as integer = 1 to NumberOfGenerators
Dim newGenerator As New DataGenerator()
Dim newTab as Ne tabPage(i.ToString)
Dim NewGrid as New DataGridView
newTab.Controls.Add(newGrid)
newGrid.DataSource = newGenerator.DataList
myGenerators.Add(newGrid)
next
End Sub
Private Sub ButtonStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonStart.Click
for each generator as dataGenerator in myGenerators
generator.StartDataThread()
next
End Sub
Private Sub ButtonChangeFormat_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonChangeFormat.Click
for each generator as dataGenerator in myGenerators
generator.ChangeDataFormat()
next
End Sub
End Class
I know that there is a lot of code but I wanted to be clear. So when I click the start button the new items start appearing, however, once they get to the bottom of the grid the scroll bar doesn't appear. If I click the Change Format button the data changes format and updates in the grid properly. I was under the impression that the ListChanged event would automatically work with a bindinglist and datagridview. I tried calling update and refresh on myDataGridView and setting datagridview.datasource to nothing and then back to DataList.
Am I missing something?

List(Of Event) in VB.NET

The following is part of a larger project, but for the purpose of this question, I have the following code:
Public MustInherit Class Class1(Of T As {System.Windows.Forms.Control, New})
Inherits System.Windows.Forms.UserControl
Friend Items As New Dictionary(Of Integer, T)
Sub Add(ByRef Item As T, ByVal Index As Integer)
Me.Items.Add(Index, Item)
AddHandler Item.Click, AddressOf Class1Click
End Sub
Public Shadows Event Click(ByVal sender As System.Object, ByVal e As System.EventArgs, ByVal Index As Integer)
Sub Class1Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
RaiseEvent Click(sender, e, DirectCast(sender, T).Index)
End Sub
End Class
Public Class Class1CheckBox
Inherits Class1(Of System.Windows.Forms.CheckBox)
End Class
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
Inherits System.Windows.Forms.Form
...
'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.MyClass1 = New Class1CheckBox()
Me.CheckBox1 = New System.Windows.Forms.CheckBox()
Me.CheckBox2 = New System.Windows.Forms.CheckBox()
Me.CheckBox3 = New System.Windows.Forms.CheckBox()
Me.CheckBox4 = New System.Windows.Forms.CheckBox()
Me.SuspendLayout()
...
Me.CheckBox1.Name = "CheckBox1"
Me.CheckBox2.Name = "CheckBox2"
Me.CheckBox3.Name = "CheckBox3"
Me.CheckBox4.Name = "CheckBox4"
...
End Sub
...
Friend WithEvents CheckBox1 As System.Windows.Forms.CheckBox
Friend WithEvents CheckBox2 As System.Windows.Forms.CheckBox
Friend WithEvents CheckBox3 As System.Windows.Forms.CheckBox
Friend WithEvents CheckBox4 As System.Windows.Forms.CheckBox
Friend WithEvents MyClass1 As Class1CheckBox
End Class
Public Class Form1
Private Sub MyClass1_Click(ByVal sender As Object, ByVal e As System.EventArgs, ByVal Index As Integer) Handles MyClass1.Click
MessageBox.Show(DirectCast(sender, CheckBox).Name)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Controls.OfType(Of CheckBox).AsParallel.ForAll(Sub(n) Me.MyClass1.Add(n, n.Index))
End Sub
End Class
The above code works beautifully. Anytime one of the four checkboxes are clicked, the click even is intercepted by the MyClass1 and is handled by MyClass1. That's what I want.
The problem is that "Click" is hardcoded. Notice, that Class1 is generic. I want for it to be able to accept any class which inherits System.Windows.Forms.Control. Some controls may have a Check event, or a hover, or a GotFocus. What I need is something as follows, I'm just not sure what the proper syntax is:
Public Class Class1CheckBox
Inherits Class1(Of System.Windows.Forms.CheckBox)
MyBase.AddEvent("Hover", <signature>...)
End Class
Public MustInherit Class Class1(Of T As {System.Windows.Forms.Control, New})
Inherits System.Windows.Forms.UserControl
Friend Items As New Dictionary(Of Integer, T)
Friend Events As New List(Of Event)
Sub AddEvent(EventName As String, ...)
Events.Add(EventName...)
End Sub
Sub Add(ByRef Item As T, ByVal Index As Integer)
Me.Items.Add(Index, Item)
For Each MyEvent As Event In Events
AddHandler ...
Next MyEvent
End Sub
'Public Shadows Event Click(ByVal sender As System.Object, ByVal e As System.EventArgs, ByVal Index As Integer)
'Sub Class1Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
' RaiseEvent Click(sender, e, DirectCast(sender, T).Index)
'End Sub
End Class
What is the proper syntax to create some kind of sequence of events, and how would I be able to raise those events?
Thanks,
What you want is not possible. Events are members, just like methods and properties. You can't write code to access any member unless you know that the type you have has that member.
Just as with methods and properties, if you want to decide what event to use at run time then you have to use Reflection.
As jmcilhinney correctly say, you need to use reflection.
Here is a simple example:
Imports System.Reflection
Public MustInherit Class Class1(Of T As {Control, New})
Private _Items As New Dictionary(Of Integer, T)
Private _Events As New Dictionary(Of String, [Event])
Protected Sub AddEvent(eventName As String, [delegate] As [Delegate])
If (Not Me._Events.ContainsKey(eventName)) Then
Dim info As EventInfo = GetType(T).GetEvent(eventName)
If (info Is Nothing) Then
Throw New ArgumentOutOfRangeException("eventName")
End If
Me._Events.Add(eventName, New [Event]([delegate], info))
End If
End Sub
Public Sub AddItem(item As T, index As Integer)
Me._Items.Add(index, item)
For Each [event] As KeyValuePair(Of String, [Event]) In Me._Events
[event].Value.Info.AddEventHandler(item, [event].Value.Delegate)
Next
End Sub
Friend Class [Event]
Friend Sub New([Delegate] As [Delegate], Info As EventInfo)
Me.[Delegate] = [Delegate]
Me.Info = Info
End Sub
Public ReadOnly [Delegate] As [Delegate]
Public ReadOnly Info As EventInfo
End Class
End Class
Public Class Class1CheckBox
Inherits Class1(Of CheckBox)
Public Sub New()
Me.AddEvent("CheckedChanged", New EventHandler(Sub(sender As Object, e As EventArgs) MsgBox(DirectCast(sender, CheckBox).Name & " is checked: " & DirectCast(sender, CheckBox).Checked.ToString())))
End Sub
End Class

VB .Net listboxes and collections of objects

I would like to move Item objects between the 2 following collections.
Private ItemsInRoom As New List(Of CItem)
Private Inv As New List(Of CItem)
I would like this to be done through 2 ListBoxes. 1 is the Inventory and the other is the Item list. How can I do this.
The CItem class has several members, only the Name of the item needs to be shown in the ListBox. I have been at this for hours, but I can't get anything to work. Does this explanation make sense in what I'm trying to do? If not, what else can I explain so someone might help me?
In your CItem class you need to override the ToString() function. That will get the name displayed in the listbox.
Public Class CItem
Public Overrides Function ToString() As String
Return Me.Name
End Function
'etc...
End Class
I think what you want is this:
Which is accomplished with the following code:
Option Explicit On
Public Class Form1
Private ItemsInRoom As New List(Of CItem)
Private ItemsInInv As New List(Of CItem)
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
MyBase.OnLoad(e)
ItemsInInv.Add(New CItem(1001, "Egret"))
ItemsInInv.Add(New CItem(1002, "Dove"))
ItemsInInv.Add(New CItem(1003, "Hawk"))
UpdateBindings()
End Sub
Public Function CheckOut(ByVal item As CItem) As Boolean
If item IsNot Nothing Then
ItemsInInv.Remove(item)
ItemsInRoom.Add(item)
Return True
End If
Return False
End Function
Public Function CheckIn(ByVal item As CItem) As Boolean
If item IsNot Nothing Then
ItemsInRoom.Remove(item)
ItemsInInv.Add(item)
Return True
End If
Return False
End Function
Public Sub UpdateBindings()
itemsInInvListBox.BeginUpdate()
itemsInInvListBox.DataSource = Nothing
itemsInInvListBox.DataSource = ItemsInInv
itemsInInvListBox.DisplayMember = "Name"
itemsInInvListBox.EndUpdate()
itemsInInvListBox.Refresh()
itemsInRoomListBox.BeginUpdate()
itemsInRoomListBox.DataSource = Nothing
itemsInRoomListBox.DataSource = ItemsInRoom
itemsInRoomListBox.DisplayMember = "Name"
itemsInRoomListBox.EndUpdate()
itemsInRoomListBox.Refresh()
End Sub
Private Sub itemsInInvListBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles itemsInInvListBox.SelectedIndexChanged
checkOutButton.Enabled = itemsInInvListBox.SelectedIndex <> -1
End Sub
Private Sub itemsInRoomListBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles itemsInRoomListBox.SelectedIndexChanged
checkInButton.Enabled = itemsInRoomListBox.SelectedIndex <> -1
End Sub
Private Sub checkOutButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles checkOutButton.Click
Dim item As CItem = CType(itemsInInvListBox.SelectedItem, CItem)
If CheckOut(item) Then
UpdateBindings()
End If
End Sub
Private Sub checkInButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles checkInButton.Click
Dim item As CItem = CType(itemsInRoomListBox.SelectedItem, CItem)
If CheckIn(item) Then
UpdateBindings()
End If
End Sub
End Class
Public Class CItem
Public Sub New(ByVal item_id As UInteger, ByVal item_name As String)
Me.m_id = item_id
Me.m_name = item_name
End Sub
Private m_name As String
Public Property Name() As String
Get
Return m_name
End Get
Set(ByVal value As String)
m_name = value
End Set
End Property
Private ReadOnly m_id As UInteger
Public ReadOnly Property ID() As UInteger
Get
Return m_id
End Get
End Property
End Class

Casting interfaces and MEF

I have the following problem with MEF:
Interface definition to be used by host:
Public Interface IExecuteDoSomething
Inherits IAddinSettings
Event DataReceived As EventHandler(Of DataReceivedEventArgs)
Function DoSomething() As Boolean
End Interface
Public Class DataReceivedEventArgs
Inherits EventArgs
Public Sub New(ByVal message As String)
Me.Message = message
End Sub
Public Message As String
End Class
extra interface needed by some other code inside the host:
Public Interface IAddinSettings
ReadOnly Property Setting() As AddinSettings
End Interface
Public Class AddinSettings
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
Public Sub New(ByVal name As String)
Me.Name = name
End Sub
End Class
The class that provides the export:
<Export(GetType(SharedLibrary.IExecuteDoSomething))> Public Class Class1
Implements SharedLibrary.IExecuteDoSomething
Implements SharedLibrary.IAddinSettings
Private _Addinsettings As New SharedLibrary.Addinsettings("Test")
Public Function DoSomething() As Boolean Implements SharedLibrary.IExecuteDoSomething.DoSomething
MsgBox("i did something")
Return True
End Function
Public Event DataReceived(ByVal sender As Object, ByVal e As SharedLibrary.DataReceivedEventArgs) Implements SharedLibrary.IExecuteDoSomething.DataReceived
Public ReadOnly Property Setting() As SharedLibrary.AddinSettings Implements SharedLibrary.IAddinSettings.Setting
Get
Return _Addinsettings
End Get
End Property
End Class
The host:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim catalog As New Hosting.AggregateCatalog
Dim d As New Hosting.DirectoryCatalog("..path to dlll..")
catalog.Catalogs.Add(d)
Dim container = New Hosting.CompositionContainer(catalog)
Dim batch As New Hosting.CompositionBatch
batch.AddPart(Me)
container.Compose(batch)
For Each dd In dos
AddHandler dd.DataReceived, AddressOf testevent
Next
End Sub
<Import()> Public dos As IEnumerable(Of SharedLibrary.IExecuteDoSomething)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each d In dos
d.DoSomething()
Next
End Sub
Private Sub testevent(ByVal sender As Object, ByVal e As SharedLibrary.DataReceivedEventArgs)
MsgBox("Event received: " & e.Message)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dosomethingelse(DirectCast(dos, System.Collections.Generic.List(Of SharedLibrary.IAddinSettings)))
End Sub
Private Sub Dosomethingelse(byval settings as IEnumerable(Of SharedLibrary.IAddinSettings))
End Sub
End Class
Everything seems to work fine until the Button2_Click routine is executed, then an InvalidCastException is thrown with the info:
Unable to cast object of type 'System.Collections.Generic.List1[SharedLibrary.IExecuteDoSomething]' to type 'System.Collections.Generic.List1[SharedLibrary.IAddinSettings]'.
How can i solve this problem, because the imported object implements both of the interfaces?
I suspect you're actually running into a covariance issue - that's the typical cause of problems like this. A List<IFoo> is not a List<IBar> even if IBar extends IFoo.
If you're using .NET 3.5, the easiest way to get round this in your case is to remove the DirectCast and instead use Enumerable.Cast:
Dosomethingelse(dos.Cast(Of SharedLibrary.IAddinSettings))