Greetins,
I am programmer from some time only, I have certain doubts in fundamentals, could you please clarify on the following:
Case 1:
Public Class BillItems
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Private _BillIdValue As String
Property BillId As String
Get
Return _BillIdValue
End Get
Set(ByVal value As String)
If Not _BillIdValue = value Then
_BillIdValue = value
End If
End Set
End Property
End Class
Case 2:
Public Class BillItems
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Property BillId As String
Get
Return BillId
End Get
Set(ByVal value As String)
If Not BillId = value Then
BillId = value
End If
End Set
End Property
End Case
Does case 1 and case 2 yield same result, I mean is a private value necessarily in there?, can we use property itself to use its own value in its Set and get statements?
Thank you.
I can't imagine that Case 2 is going to run without causing a stack-overflow exception. You are essentially making an infinite loop that is going to constantly call itself.
Case 1 would be the right way to do it.
If you are using .Net 4 you could just do this (without the further Get/Set code):
Property BillId As String
This will generate the private member variable (_BillId) for you.
Edit:
You could try this to raise the event:
Property BillId As String
Get
Return _BillIdValue
End Get
Set(ByVal value As String)
If Not _BillIdValue = value Then
_BillIdValue = value
NotifyPropertyChanged("BillId")
End If
End Set
End Property
In this article on MSDN about Auto-Implemented Properties you can read that a property requires a standard syntax when you
Add code to the Get or Set procedure of a property, such as code to validate incoming values in the Set procedure. For example, you might want to verify that a string that represents a telephone number contains the required number of numerals before setting the property value.
Therefore, because you implement IPropertyChanged interface, you need to add code to the setter.
and write something like this.
Property BillId As String
Get
Return _BillIdValue
End Get
Set(ByVal value As String)
If Not _BillIdValue = value Then
_BillIdValue = value
NotifyPropertyChanged("BillID")
End If
End Set
End Property
The second case is clearly wrong. (Infinite loop as someone else has already said)
Related
I have a couple of classes with properties. I would like to be able to iterate through the properties of the class and get the value of the property. I included a sample of the class along with how I am looping the properties. Need help with understanding the usage of "GetValue" and "SetValue"
Private Sub loadValues()
Dim mySample As New Sample
Dim props As PropertyInfo() = mySample.GetType().GetProperties()
mySample.Test2 = True
Console.WriteLine(mySample.Test2)
For Each prop In props
Console.WriteLine(prop.Name)
'This will loop through all the properties in the Sample clasee
'How can I get and change the value of each of the properties?
prop.GetValue(mySample, Nothing) '?????
prop.SetValue(mySample, False, Nothing) '?????
Next
End Sub
Here is the sample of the class
Public Class Sample
Public Name As String = "Sample"
Public _Cut As Boolean = False
Private _Test1 As Boolean
Private _Test2 As Boolean
Private _Test3 As Boolean
Public Property Cut(ByVal CabType As String) As Boolean
Get
Return _Cut
End Get
Set(ByVal value As Boolean)
_Cut = value
End Set
End Property
Public Property Test1() As Boolean
Get
Return _Test1
End Get
Set(ByVal value As Boolean)
_Test1 = value
End Set
End Property
Public Property Test2() As Boolean
Get
Return _Test2
End Get
Set(ByVal value As Boolean)
_Test2 = value
End Set
End Property
Public Property Test3() As Boolean
Get
Return _Test3
End Get
Set(ByVal value As Boolean)
_Test3 = value
End Set
End Property
End Class
The Cut property is indexed, so you need to pass some index value to PropertyInfo.GetValue. You may see that the signature of GetValue is
Public Overridable Function GetValue(obj As Object, index() As Object) As Object
so the index argument needs to be an array when indexed. Simply pass your Nothing as a single element index {Nothing} in that case. You can tell if there are index parameters by checking if PropertyInfo.GetIndexParameters() has anything
Private Sub loadValues()
Dim mySample As New Sample
Dim props As PropertyInfo() = mySample.GetType().GetProperties()
mySample.Test2 = True
Console.WriteLine(mySample.Test2)
For Each prop In props
Console.WriteLine(prop.Name)
If prop.GetIndexParameters().Any() Then
prop.GetValue(mySample, {Nothing})
prop.SetValue(mySample, False, {Nothing})
Else
prop.GetValue(mySample, Nothing)
prop.SetValue(mySample, False, Nothing)
End If
Next
End Sub
However, having an indexed property then iterating through all the properties arbitrarily may not make sense when you need to pass a specific index to properly access the property.
I'm testing out PetaPoco to determine if it meets our needs. I was under the impression that it would delve into my class and see the private properties that I've marked up as valid columns. Unfortunately, it's not behaving as expected. Can you please take a look and let me know if I'm doing something wrong.
My test class:
Imports PetaPoco
<PetaPoco.TableName("PaulTest")>
<PetaPoco.PrimaryKey("ID")>
Public Class PaulTest
<PetaPoco.Column("ID")>
Private Property pvtID As Integer
Private pvtName As String
Private Sub New()
End Sub
Public Sub New(name As String)
If String.IsNullOrEmpty(name) Then
Throw New ArgumentException("Passed Name is empty")
End If
Me.pvtName = name
End Sub
<PetaPoco.Ignore>
Public ReadOnly Property ID As Integer
Get
Return pvtID
End Get
End Property
<PetaPoco.Column("Name")>
Public Property Name As String
Get
Return pvtName
End Get
Set(value As String)
If String.IsNullOrEmpty(value) Then
Throw New ArgumentException("Passed Name is empty")
End If
Me.pvtName = value
End Set
End Property
End Class
The call to the DB (_db is a PetaPoco database object)
Return (_db.Fetch(Of Peta.Domain.PaulTest)(";EXEC selAllPaulTest")).OrderBy(Function(PaulTest) (PaulTest.ID)).ToList()
What's in the database
ID Name
107 Paul
What's being returned:
PaulTest.ID = 0
PaulTest.pvtID = 0
PaulTest.Name = "Paul"
PaulTest.pvtName = "Paul"
<PetaPoco.Ignore> attribute instructs PetaPoco to ignore the column during mapping. As such, the property Id will always be returning the default value of 0.
If you want to prevent the Id property from being modified, comment our or delete the attribute and add a private setter to the Id property as in the following code snippet.
' <PetaPoco.Ignore>
Public Property Id As Integer
Get
Return pvtID
End Get
Private Set(value As Integer)
pvtID = value
End Set
End Property
My problem occurs in a Windows Phone 8.1 Silverlight VB application. The CatDataContext defines a table Books with items Title and a foreign key _seriesID, with belongs to a table Series.
<Table()>
Public Class Series
Implements INotifyPropertyChanged, INotifyPropertyChanging
' Define ID: private field, public property, and database column.
Private _seriesID As Integer
<Column(IsPrimaryKey:=True, IsDbGenerated:=True, DbType:="INT NOT NULL Identity", CanBeNull:=False,
AutoSync:=AutoSync.OnInsert)>
Public Property SeriesID() As Integer
Get
Return _seriesID
End Get
Set(ByVal value As Integer)
If _seriesID <> value Then
NotifyPropertyChanging("SeriesID")
_seriesID = value
NotifyPropertyChanged("SeriesID")
End If
End Set
End Property
' Define name: private field, public property, and database column.
Private _Name As String
<Column()>
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
If _Name <> value Then
NotifyPropertyChanging("Name")
_Name = value
NotifyPropertyChanged("Name")
End If
End Set
End Property
#Region "INotifyPropertyChanged Members"
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
' Used to notify that a property changed
Private Sub NotifyPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
#End Region
#Region "INotifyPropertyChanging Members"
Public Event PropertyChanging As PropertyChangingEventHandler Implements INotifyPropertyChanging.PropertyChanging
' Used to notify that a property is about to change
Private Sub NotifyPropertyChanging(ByVal propertyName As String)
RaiseEvent PropertyChanging(Me, New PropertyChangingEventArgs(propertyName))
End Sub
#End Region
End Class
<Table()>
Public Class Book
Implements INotifyPropertyChanged, INotifyPropertyChanging
' Define ID: private field, public property, and database column.
Private _bookID As Integer
<Column(IsPrimaryKey:=True, IsDbGenerated:=True, DbType:="INT NOT NULL Identity", CanBeNull:=False,
AutoSync:=AutoSync.OnInsert)>
Public Property BookID() As Integer
Get
Return _bookID
End Get
Set(ByVal value As Integer)
If _bookID <> value Then
NotifyPropertyChanging("BookID")
_bookID = value
NotifyPropertyChanged("BookID")
End If
End Set
End Property
' Define title: private field, public property, and database column.
Private _title As String
<Column()>
Public Property Title() As String
Get
Return _title
End Get
Set(ByVal value As String)
If _title <> value Then
NotifyPropertyChanging("Title")
_title = value
NotifyPropertyChanged("Title")
End If
End Set
End Property
' Internal column for the associated series ID value.
<Column()>
Friend _seriesID As Integer
Private _series As EntityRef(Of Series)
<Association(Storage:="_series", ThisKey:="_seriesID", OtherKey:="SeriesID")>
Public Property BookSeries() As Series
Get
Return _series.Entity
End Get
Set(ByVal value As Series)
NotifyPropertyChanging("BookSeries")
_series.Entity = value
If value IsNot Nothing Then
_seriesID = value.SeriesID
End If
NotifyPropertyChanged("BookSeries")
End Set
End Property
#Region "INotifyPropertyChanged Members"
Public Event PropertyChanged As PropertyChangedEventHandler Implements NotifyPropertyChanged.PropertyChanged
' Used to notify that a property changed
Private Sub NotifyPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
#End Region
#Region "INotifyPropertyChanging Members"
Public Event PropertyChanging As PropertyChangingEventHandler Implements INotifyPropertyChanging.PropertyChanging
' Used to notify that a property is about to change
Private Sub NotifyPropertyChanging(ByVal propertyName As String)
RaiseEvent PropertyChanging(Me, New PropertyChangingEventArgs(propertyName))
End Sub
#End Region
Updating of the field Title alone, or the fields Title and _seriesID works fine. However when I only change the _seriesID then no update of the underlying database is done. In this case .GetModifiedMembers shows no modifications.
A reference to a demo project showing this problem is given here: demo project.
Thanks for your attention.
_seriesID (in Book) is just a member variable. You can set it from outside Book because it is Friend, but further nothing happens.
Title, on the other hand, is a property that fires NotifyPropertyChanged. That means that the context is notified that the Book object has been modified if you change Title.
So if you change _seriesID and Title, the Book object is marked as modified and saved, along with the changed value of _seriesID. But if you change _seriesID alone, the object remains 'unchanged'.
I think this is generated code (LINQ-to-SQL? I don't really recognize it) and you shouldn't modify it manually. If you want _seriesID to be changed, you have to set BookSeries.
I have some Linq to SQL table classes that are joined together. I currently have it bound to a treeview using just the LINQ to SQL query. It works, but it doesn't show when stuff is added or removed from the database.
I implemented INotifyPropertyChanged but it isn't updating the treeview.
I also tried using Bindable Linq, but it doesn't seem to make a difference.
I found an example of a way to easily create ObservableCollections without having to create more classes: jimlynn.wordpress.com/2008/12/09/using-observablecollection-with-linq/, (which is kind of important because I have a future project looming that will require interacting with a lot of tables (30 or so) and just creating the Linq to SQL classes is going to be a pain).
Property ModelQuery As ObservableCollection(Of dbModels) = New ObservableCollection(Of dbModels)().PopulateFrom(From mm In tblModels.AsBindable Order By mm.ModelName)
Is this a good way to go, or am I going to have to create a separate ObservableCollection and maintain them both in code. If I'm going to use this binding stuff, I'm really looking for a way to have stuff just linked together so I don't have to update multiple structures whenever a change is made.
Main table:
<Table(Name:="Models")> Public Class dbModels
Implements INotifyPropertyChanged
Private _changed As Boolean
Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(ByVal Propertyname As String)
If Not Propertyname.Contains("Changed") Then
Changed = True
End If
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Propertyname))
End Sub
Public Property Changed() As Boolean
Get
Return _changed
End Get
Set(ByVal value As Boolean)
If _changed <> value Then
_changed = value
OnPropertyChanged("Changed")
End If
End Set
End Property
Private _ModelID As Integer
<Column(Storage:="_ModelID", DbType:="int IDENTITY NOT NULL", IsPrimaryKey:=True, IsDbGenerated:=True, Name:="ModelID")> _
Public Property ModelID() As Integer
Get
Return Me._ModelID
End Get
Set(value As Integer)
Me._ModelID = value
End Set
End Property
Private _ModelName As String
<Column(Storage:="_ModelName", DbType:="Varchar(200)", Name:="ModelName")> _
Public Property ModelName() As String
Get
Return Me._ModelName
End Get
Set(value As String)
Me._ModelName = value
End Set
End Property
Private _ModelYears As EntitySet(Of dbModelYears) = New EntitySet(Of dbModelYears)
<Association(Storage:="_ModelYears", DeleteRule:="CASCADE", OtherKey:="ModelID")> _
Public Property ModelYears As EntitySet(Of dbModelYears)
Get
Return _ModelYears
End Get
Set(value As EntitySet(Of dbModelYears))
_ModelYears.Assign(value)
End Set
End Property
End Class
Joined table:
<Table(Name:="ModelYears")> Public Class dbModelYears
Implements INotifyPropertyChanged
Private _changed As Boolean
Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(ByVal Propertyname As String)
If Not Propertyname.Contains("Changed") Then
Changed = True
End If
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Propertyname))
End Sub
Public Property Changed() As Boolean
Get
Return _changed
End Get
Set(ByVal value As Boolean)
If _changed <> value Then
_changed = value
OnPropertyChanged("Changed")
End If
End Set
End Property
Private _ModelYearID As Integer
<Column(Storage:="_ModelYearID", DbType:="int IDENTITY NOT NULL", IsPrimaryKey:=True, IsDbGenerated:=True, Name:="ModelYearID")> _
Public Property ModelYearID() As Integer
Get
Return Me._ModelYearID
End Get
Set(value As Integer)
Me._ModelYearID = value
End Set
End Property
Private _ModelID As Integer
<Column(Storage:="_ModelID", DbType:="int", Name:="ModelID")> _
Public Property ModelID() As Integer
Get
Return Me._ModelID
End Get
Set(value As Integer)
Me._ModelID = value
End Set
End Property
Private _ModelYear As String
<Column(Storage:="_ModelYear", DbType:="Varchar(50)", Name:="ModelYear")> _
Public Property ModelYear() As String
Get
Return Me._ModelYear
End Get
Set(value As String)
Me._ModelYear = value
End Set
End Property
End Class
Implementing INotifyPropertyChanged or using ObservableCollection wont notify you of changes in the database. You are going to have to execute the query every time you want to retrieve new data from the database.
Alternatively you could possibly use SqlDependency to set up a query notification dependency between your application and an instance of SQL Server.
EDIT:
From comments.
To hook up the PropertyChanged event of the items in the collection.
For Each item As var In itemsCollection
Dim notifyItem = TryCast(item, INotifyPropertyChanged)
If item IsNot Nothing Then
AddHandler notifyItem.PropertyChanged, AddressOf ItemChanged
End If
Next
Public Sub ItemChanged(sender As Object, e As PropertyChangedEventArgs)
'Handle event
End Sub
Lets say I have a class called "Item" and "SubItems"
Public Class SubItem
Private _SubItemName As String
Public Property SubItemName() As String
Get
Return _SubItemName
End Get
Set(ByVal value As String)
_SubItemName = value
End Set
End Property
End Class
<DataServiceKey("Name")> _
Public Class Item
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
Private _SubItems As List(Of SubItem)
Public Property SubItems() As List(Of SubItem)
Get
Return _SubItems
End Get
Set(ByVal value As List(Of SubItem))
_SubItems = value
End Set
End Property
End Class
How would I create a service that would return a list of Items and upon looking up an individual item I would be able to see the sub items.
You can check out WCF Data Servies reflection provider, e.g.,
http://blogs.msdn.com/b/alexj/archive/2010/06/11/tip-56-writing-an-odata-service-using-the-reflection-provider.aspx
http://msdn.microsoft.com/en-us/library/dd728281.aspx
Hope this helps.