NotifyPropertyChanged Doesn't work, why? - inotifypropertychanged

I am trying to call a Property with INotifyPropertyChanged from ClassB to ClassA, but this doesn't work! What am I doing wrong?
Class A
Public Class ClassA
Implements System.ComponentModel.INotifyPropertyChanged
Public Event PropertyChanged(ByVal sender As Object, ByVal e As
System.ComponentModel.PropertyChangedEventArgs) Implements
System.ComponentModel.INotifyPropertyChanged.Prope rtyChanged
Protected Overridable Sub OnPropertyChanged(ByVal e As
System.ComponentModel.PropertyChangedEventArgs)
RaiseEvent PropertyChanged(Me, e)
End Sub
Private m_prop1 As String
Public Property Prop1() As String
Get
Return m_prop1
End Get
Set(ByVal value As String)
m_prop1 = value
End Set
End Property
End Class
Class B
Public Class Class B
Inherits Class A
Private m_prop2 As String
Public Property Prop2() As String
Get
Return m_prop2
End Get
Set(ByVal value As String)
m_prop2 = value
Dim e As New System.ComponentModel.PropertyChangedEventArgs("Prop1")
OnPropertyChanged(e)
End Set
End Property
End Class
This example works!!.
Class A
Public Class ClassA
Implements System.ComponentModel.INotifyPropertyChanged
Public Event PropertyChanged(ByVal sender As Object, ByVal e As
System.ComponentModel.PropertyChangedEventArgs) Implements
System.ComponentModel.INotifyPropertyChanged.Prope rtyChanged
Protected Overridable Sub OnPropertyChanged(ByVal e As
System.ComponentModel.PropertyChangedEventArgs)
RaiseEvent PropertyChanged(Me, e)
End Sub
Private m_prop1 As String
Public Property Prop1() As String
Get
Return m_prop1
End Get
Set(ByVal value As String)
m_prop1 = value
End Set
End Property
End Class
Class B
Public Class Class B
Inherits Class A
Private m_prop2 As String
Public Property Prop2() As String
Get
Return m_prop2
End Get
Set(ByVal value As String)
m_prop2 = value
Dim e As New System.ComponentModel.PropertyChangedEventArgs("Prop3")
OnPropertyChanged(e)
End Set
End Property
Private m_prop3 As String
Public Property Prop3() As String
Get
Return m_prop3
End Get
Set(ByVal value As String)
m_prop3 = value
End Set
End Property
End Class
But I want to replace that the PropertyChanged "Prop3" call "Prop1" from another class. This is possible?

I solve it, I create a variable m_ClassA in ClassB and then I put it as a parameter "sender" of the OnPropertyChanged method.
Class A
Public Class ClassA
Implements System.ComponentModel.INotifyPropertyChanged
Public Event PropertyChanged(ByVal sender As Object, ByVal e As
System.ComponentModel.PropertyChangedEventArgs) Implements
System.ComponentModel.INotifyPropertyChanged.Prope rtyChanged
Protected Overridable Sub OnPropertyChanged(ByVal sender As Object, ByVal e As
System.ComponentModel.PropertyChangedEventArgs)
RaiseEvent PropertyChanged(sender, e)
End Sub
Private m_prop1 As String
Public Property Prop1() As String
Get
Return m_prop1
End Get
Set(ByVal value As String)
m_prop1 = value
End Set
End Property
End Class
Class B
Public Class ClassB
Inherits ClassA
Private m_ClassA as ClassA
Public Sub New(ByVal c as ClassA)
m_ClassA = c
End Sub
Private m_prop2 As String
Public Property Prop2() As String
Get
Return m_prop2
End Get
Set(ByVal value As String)
m_prop2 = value
Dim e As New System.ComponentModel.PropertyChangedEventArgs("Prop1")
OnPropertyChanged(m_ClassA,e)
End Set
End Property
End Class

Related

Trigger parent property

How Can I update parent property? My example code below.
When Demo2 property (Class2) set a value, I want run code Demo property (Class1)
Any help would be appreciated.
'My example code
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim d As New Class1
d.Demo.Demo2 = True ' Set value
End Sub
End Class
Public Class Class1
Dim c As Class2
Public Sub New()
c = New Class2
End Sub
Public Property Demo As Class2
Get
Return c
End Get
Set(value As Class2)
'**How can I run this row?**
c = value
End Set
End Property
End Class
Public Class Class2
Private b As Boolean
Public Property Demo2 As Boolean
Get
Return b
End Get
Set(value As Boolean)
b = value
End Set
End Property
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

Visual Basic - Handle events for class within a list

Public Class EquipmentCollection
{
Public Property EquipmentList As List(Of Equipment)
}
Public Class Equipment
{
Public Event CalculateFired
Public Sub Calculate
RaiseEvent CalculateFired
End Sub
}
How can I handle the CalculateFired event on the Equipment class within the EquipmentCollection class?
.NET 3.5, VB
The BindingList has events to catch those changes, but it would require your Equipment class to implement the INotifyPropertyChanged interface:
Public Class Equipment
Implements INotifyPropertyChanged
Public Event PropertyChanged(ByVal sender As Object, _
ByVal e As PropertyChangedEventArgs) _
Implements INotifyPropertyChanged.PropertyChanged
Private _Calculation As Decimal
Public Sub Calculate(ByVal newNumber As Decimal)
Me.Calculation = newNumber
End Sub
Property Calculation() As Decimal
Get
Return _Calculation
End Get
Set(ByVal value As Decimal)
If value <> _Calculation Then
_Calculation = value
RaiseEvent PropertyChanged(Me, _
New PropertyChangedEventArgs("Calculation"))
End If
End Set
End Property
End Class
Your EquipmentCollection class would listen for the changed event:
Public Class EquipmentCollection
Private WithEvents _EquipmentList As New BindingList(Of Equipment)
Public ReadOnly Property EquipmentList() As BindingList(Of Equipment)
Get
Return _EquipmentList
End Get
End Property
Private Sub EquipmentList_ListChanged(ByVal sender As Object, _
ByVal e As ListChangedEventArgs) _
Handles _EquipmentList.ListChanged
If e.ListChangedType = ListChangedType.ItemChanged Then
If e.PropertyDescriptor IsNot Nothing AndAlso _
e.PropertyDescriptor.Name = "Calculation" Then
MessageBox.Show("New Calculation = " & _
_EquipmentList.Item(e.NewIndex).Calculation.ToString)
End If
End If
End Sub
End Class
Simple implementation:
Dim ec As New EquipmentCollection
ec.EquipmentList.Add(New Equipment)
ec.EquipmentList.Add(New Equipment)
ec.EquipmentList.Last.Calculate(110.5)
This worked for me.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ec As New EquipmentCollection
Dim eq As New Equipment
Dim el As New List(Of Equipment)
eq = New Equipment
el.Add(eq)
eq = New Equipment
el.Add(eq)
eq = New Equipment
el.Add(eq)
eq = New Equipment
el.Add(eq)
eq = New Equipment
el.Add(eq)
eq = New Equipment
el.Add(eq)
eq = New Equipment
el.Add(eq)
ec.EquipmentList = el
ec.EquipmentList.Item(2).Calculate()
End Sub
End Class
Public Class EquipmentCollection
Private WithEvents _EquipmentList As New List(Of Equipment)
Public Property EquipmentList As List(Of Equipment)
Get
Return _EquipmentList
End Get
Set(value As List(Of Equipment))
Dim counter As Integer
_EquipmentList = value
For counter = 0 To _EquipmentList.Count - 1
AddHandler _EquipmentList.Item(counter).CalculateFired, AddressOf HandleCalculateFired
Next
End Set
End Property
Private Sub HandleCalculateFired()
MsgBox("calc was fired")
End Sub
End Class
Public Class Equipment
Public Event CalculateFired()
Public Sub Calculate()
RaiseEvent CalculateFired()
End Sub
End Class
You will need to add an event handler in EquipmentCollection to each object in the equipment list you want to handle the event for.
See the MSDN page on events and event handlers.
http://msdn.microsoft.com/en-us/library/2z7x8ys3%28v=vs.80%29.aspx

VB.NET: Fields from a class

I have a class being populated from comma separated rows in a text file.
I am trying to have the name property of each object appear in a listbox, then have the rest of the properties of a selected object show up in text boxes. How do I load the properties of the selected object to the correct textbox?
I'm assuming that the class you fill has a list of the objects and that you have already figured out how to fill the listbox...
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
For Each obj As YourObjectType In YourClass.CollectionOfYourObjects
If obj.Name = ListBox1.SelectedItem.ToString Then
Textbox1.Text = obj.Property1
Textbox2.Text = obj.Property2
End If
Next
End Sub
You have one TextBox for every Property and the number of properties is static, isn't it?
You have to set the DisplayMember to the Property's name that you want to see in the Listbox.
This simplified sample should work:
Public Class ListBox
Private Sub ListBox_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim allFoos As New List(Of FooClass)
For i As Int32 = 1 To 10
Dim foo As New FooClass
foo.Name = "Foo_" & i
foo.Prop1 = "Prop1_" & i
foo.Prop2 = "Prop2_" & i
foo.Prop3 = "Prop3_" & i
allFoos.Add(foo)
Next
Me.ListBox1.DataSource = allFoos
Me.ListBox1.DisplayMember = "Name"
End Sub
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Dim foo As FooClass = DirectCast(ListBox1.SelectedItem, FooClass)
Me.TxtName.Text = foo.Name
Me.TxtProp1.Text = foo.Prop1.ToString
Me.TxtProp2.Text = foo.Prop2.ToString
Me.TxtProp3.Text = foo.Prop3.ToString
End Sub
End Class
Class FooClass
Private _name As String
Private _prop1 As Object
Private _prop2 As Object
Private _prop3 As Object
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Property Prop1() As Object
Get
Return _prop1
End Get
Set(ByVal value As Object)
_prop1 = value
End Set
End Property
Public Property Prop2() As Object
Get
Return _prop2
End Get
Set(ByVal value As Object)
_prop2 = value
End Set
End Property
Public Property Prop3() As Object
Get
Return _prop3
End Get
Set(ByVal value As Object)
_prop3 = value
End Set
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))