Practical Learning: Introducing Array Serialization
|
|
- If you want to follow this exercise, start Microsoft Visual Basic
- To start a new application, on the main menu, click File -> New
Project...
- In the Templates list, click Windows Application
- Set the Name to SolasPropertyRental1 and click OK
- In the Solution Explorer, right-click Form1.vb and click Rename
- Type RentalProperties.vb and press Enter
- From the Toolbox, click ListView and click the form
- While the list view is still selected on the form, in the Properties
window, click Columns and click its ellipsis button
- Create the following columns:
(Name) |
Text |
TextAlign |
Width |
colPropertyIndex |
# |
Right |
30 |
colPropertyNumber |
Property # |
|
70 |
colPropertyType |
Property Type |
|
100 |
colPropertyCondition |
Condition |
|
80 |
colBedrooms |
Bedrooms |
Right |
|
colBathrooms |
Bathrooms |
Right |
70 |
colMonthlyRent |
Monthly Rent |
Right |
80 |
- Click OK
- Complete the design of the form as follows:
|
Control |
Name |
Text |
Other Properties |
ListView |
lvwProperties |
|
FullRowSelect: True
GridLines: True
View: Details
Anchor: Top, Bottom, Left, Right |
Button |
btnNewProperty |
New Property |
Anchor: Bottom, Left |
Button |
btnClose |
Close |
Anchor: Bottom, Right |
|
- To create a new form, on the main menu, click Project -> Add New
Item...
- In the Templates list, click Windows Form
- Set the Name to NewProperty and click Add
- Design the form as follows:
|
Control |
Name |
Text |
Other Properties |
Label |
|
Property Type: |
|
Button |
btnOK |
OK |
|
Combo Box |
cboPropertyTypes |
Unknown |
Items:
Apartment
Single Family
Townhouse
Unknown |
Button |
btnOK |
OK |
DialogResult: OK |
Label |
|
Property Condition: |
|
Combo Box |
cboPropertyConditions |
Unknown |
Items:
Excellent
Good
Bad Shape
Unknown |
Button |
btnCancel |
Cancel |
DialogResult: Cancel |
Label |
|
Bedrooms: |
|
TextBox |
txtBedrooms |
0 |
TextAlign: Right |
Label |
|
Bathrooms: |
|
TextBox |
txtBathrooms |
0.00 |
TextAlign: Right |
Label |
|
Monthly Rent:
|
|
TextBox |
txtMonthlyRent |
0.00 |
|
Form |
|
|
FormBorderStyle: FixedDialog
AcceptButton: btnOK
CancelButton: btnCancel
StartPosition: CenterScreen
MaximumBox: False
MinimumBox: False
ShowInTaskbar: False |
|
- Save all
Using an Indexed Property |
|
The application we are creating is used by a property rental
company to review its available products. To manage the houses and apartments
to rent, we will create a class that holds a property. Because our application
is list-based, we will create an indexed property in a class so we can access
each property with an index applied to an instance of the that class.
One of the problems with an array is that its list of items
must be established in the beginning, but in our application we want the user to
be able to add an item to the array. In the next section, we will see that, when
the application starts, we create a default list of items but we will still
give the user the ability to create or add items. To solve the problem of
monitoring the items in the list, we will add a flag to each property. When a
default item has not been set, this flag will indicate it. Eventually, when a
user adds an item, we will change this flag to indicate that the property has
been changed from its default values. We could use a Boolean value for this flag to hold a true or a false
result but it is sometimes a little complex to serialize some Boolean values of
a collection. For this reason, we will make the flag a numeric value. Before a property has been set, this flag will hold a 0 value.
When a property has been set, this flag will become 1.
One of the problems with an array is that, when
creating it, you must specify the number of items in the list. This is
because, from the beginning, the list uses a fixed number of items. This
also implies that you cannot add an item that increases the volume of the
collection. Because the number of items is fixed, after the list has been
created, you can only replace an existing item.
In our application, we need to overcome or at least go
around these limitations of arrays. There are various actions
we can take. To start, when the application is launched, we will create a
list of items but we will fill out each item with insignificant default
values. This simply allows us to create a complete array.
Practical Learning: Creating an Indexed Property
|
|
- To create a new class, on the main menu, click Project -> Add Class...
- In the Templates list, make sure Class is selected.
Set the Name to RentalProperty and click Add
- Change the header file as follows:
Imports System
<Serializable()> Public Class RentalProperty
' These are the characteristics of a property
Dim propCode As Long
Dim type As String
Dim cond As String
Dim beds As Short
Dim baths As Double
Dim val As Double
' This flag is used to specify whether a property
' still holds the default values or it has
' previously been updated
Dim CreationFlag As Integer
' This constructor is used to create
' default values for a property
Public Sub New()
Dim rnd As Random = New Random
propCode = rnd.Next(100000, 999999)
type = "Unknown"
cond = "Unknown"
beds = 0
baths = 0.0
val = 0.0
CreationFlag = 0
End Sub
Public Property PropertyCode() As Long
Get
Return propCode
End Get
Set(ByVal value As Long)
propCode = value
End Set
End Property
Public Property PropertyType() As String
Get
Return type
End Get
Set(ByVal value As String)
type = value
End Set
End Property
Public Property PropertyCondition() As String
Get
Return cond
End Get
Set(ByVal value As String)
cond = value
End Set
End Property
Public Property Bedrooms() As Short
Get
Return beds
End Get
Set(ByVal value As Short)
beds = value
End Set
End Property
Public Property Bathrooms() As Double
Get
If baths <= 0 Then
Return 0.0
Else
Return baths
End If
End Get
Set(ByVal value As Double)
baths = value
End Set
End Property
Public Property MonthlyRent() As Double
Get
If val <= 0 Then
Return 0.0
Else
Return val
End If
End Get
Set(ByVal value As Double)
val = value
End Set
End Property
Public Overrides Function ToString() As String
Return "Property #: " & PropertyCode &
vbCrLf & "Type: " & PropertyType &
vbCrLf & "Condition: " & PropertyCondition &
vbCrLf & "Bedrooms: " & Bedrooms &
vbCrLf & "Bathrooms: " & Bathrooms &
vbCrLf & "Monthly Rent: " & MonthlyRent.ToString("C")
End Function
End Class
- To create a new class, on the main menu, click Project -> Add Class...
- In the Templates list, make sure Class is selected.
Set the Name to PropertyListing and click Add
- Change the file as follows:
Imports System.IO
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary
Public Class PropertyListing
Public Dim props(100) As RentalProperty ' = New RentalProperty()
Public Sub New()
' Check if the default list of properties has never been created.
' If there is no default list of properties,
' Then create it and save the file
If Not File.Exists("Properties.prp") Then
CreateDefaultListing()
End If
' Since we have a file that holds the list of properties
' open it and store the properties in our array
OpenProperties()
End Sub
Public Property RentalProperty(ByVal index As Integer) As RentalProperty
Get
If (index >= 0) And (index < 100) Then
Return props(index)
Else
Return Nothing
End If
End Get
Set(ByVal value As RentalProperty)
props(index) = value
End Set
End Property
Public Sub SaveProperties()
Dim strFilename As String = "Properties.prp"
Dim fstProperties As FileStream = New FileStream(strFilename,
FileMode.Create)
Dim bfmProperties As BinaryFormatter = New BinaryFormatter
Try
bfmProperties.Serialize(fstProperties, props)
Catch ex As ArgumentNullException
MsgBox("The properties listing is not available")
Catch exc As SerializationException
MsgBox("The listing could not be saved")
Finally
fstProperties.Close()
End Try
End Sub
Public Sub CreateDefaultListing()
Dim rndNumber As Random = New Random
Dim i As Integer
Dim rental As RentalProperty
For i = 0 To 100
rental = New RentalProperty
rental.PropertyCode = rndNumber.Next(100000, 999999)
rental.PropertyType = "Unknown"
rental.PropertyCondition = "Unknown"
rental.Bedrooms = 0
rental.Bathrooms = 0
rental.MonthlyRent = 0.0
rental.CreationFlag = 0
props(i) = rental
Next
SaveProperties()
End Sub
Public Sub OpenProperties()
Dim strFilename As String = "Properties.prp"
Dim fstProperties As FileStream = Nothing
Dim bfmProperties As BinaryFormatter = Nothing
' If the list of properties had already been created
' then open it
If File.Exists(strFilename) Then
Try
fstProperties = New FileStream(strFilename,
FileMode.Open)
bfmProperties = New BinaryFormatter
props = bfmProperties.Deserialize(fstProperties)
Catch ex As ArgumentNullException
MsgBox("The properties listing is not available")
Catch exc As SerializationException
MsgBox("The listing could not be opened")
Finally
fstProperties.Close()
End Try
else
Return
End If
End Sub
End Class
- Save all
Adding or Updating an Item
|
|
To give the user the ability to add a property to the list,
we will look for an item whose creation flag is set to 0. When we find a flag
with that value, we will consider that its corresponding property has not been
set. Once we find that property, we will replace it with the values of the new
property.
As discussed so far, our array will contain both default and appropriate
properties. Default properties are those that contain unrecognizable values. To
give a good impression of a list of properties that can be added to, there is no
reason to display the properties that have never been updated by the user. We
will show only properties that the user know have good values. To identify these
properties, once again the flag we created in the class of properties will be
helpful. When we want to display the properties, we will check the status or
value of this property. If it is set to 0, we will not display the property.
Practical Learning: Displaying the Properties
|
|
- Display the first form and double-click an empty area of its body
- On top of the Load event, create a new method and implement the Load event as follows:
Public Class RentalProperties
Public Sub ShowProperties()
Dim properties As PropertyListing = New PropertyListing
properties.OpenProperties()
lvwProperties.Items.Clear()
Dim i As Integer
For i = 0 To 100
Dim iFlag As Integer = properties.props(i).CreationFlag
If iFlag <> 0 Then
Dim lvi As ListViewItem =
lvwProperties.Items.Add((i + 1).ToString())
lvi.SubItems.Add(properties.props(i).PropertyCode.ToString())
lvi.SubItems.Add(properties.props(i).PropertyType)
lvi.SubItems.Add(properties.props(i).PropertyCondition)
lvi.SubItems.Add(properties.props(i).Bedrooms.ToString())
lvi.SubItems.Add(properties.props(i).Bathrooms.ToString())
lvi.SubItems.Add(properties.props(i).MonthlyRent.ToString("C"))
End If
Next
End Sub
Private Sub Form1Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load
ShowProperties()
End Sub
End Class
- In the Class Name combo box, select btnNewProperty
- In the Method Name combo box. select Click
- Implement the event as follows:
Public Class RentalProperties
Public Sub ShowProperties()
Dim properties As PropertyListing = New PropertyListing
properties.OpenProperties()
lvwProperties.Items.Clear()
Dim i As Integer
For i = 0 To 100
Dim iFlag As Integer = properties.props(i).CreationFlag
If iFlag <> 0 Then
Dim lvi As ListViewItem =
lvwProperties.Items.Add((i + 1).ToString())
lvi.SubItems.Add(properties.props(i).PropertyCode.ToString())
lvi.SubItems.Add(properties.props(i).PropertyType)
lvi.SubItems.Add(properties.props(i).PropertyCondition)
lvi.SubItems.Add(properties.props(i).Bedrooms.ToString())
lvi.SubItems.Add(properties.props(i).Bathrooms.ToString())
lvi.SubItems.Add(properties.props(i).MonthlyRent.ToString("C"))
End If
Next
End Sub
Private Sub Form1Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load
ShowProperties()
End Sub
Private Sub btnNewPropertyClick(ByVal sender As Object,
ByVal e As System.EventArgs) Handles btnNewProperty.Click
Dim dlgProperty As NewProperty = New NewProperty
Dim i As Integer
If dlgProperty.ShowDialog() =
System.Windows.Forms.DialogResult.OK Then
Dim listing As PropertyListing = New PropertyListing
For i = 0 To 100
If listing.props(i).CreationFlag = 0 Then
Try
listing.props(i).PropertyType =
dlgProperty.cboPropertyTypes.Text()
Catch ex As FormatException
MsgBox("Invalid Property Type")
End Try
Try
listing.props(i).PropertyCondition =
dlgProperty.cboPropertyConditions.Text()
Catch exc As FormatException
MsgBox("Invalid Property Condition")
End Try
Try
listing.props(i).Bedrooms =
Short.Parse(dlgProperty.txtBedrooms.Text)
Catch exc As FormatException
MsgBox("Invalid Bedroom Value")
End Try
Try
listing.props(i).Bathrooms =
CDbl(dlgProperty.txtBathrooms.Text)
Catch excp As FormatException
MsgBox("Invalid Bathroom Value")
End Try
Try
listing.props(i).MonthlyRent =
CDbl(dlgProperty.txtMonthlyRent.Text)
Catch excpt As FormatException
MsgBox("Unrecognizable Monthly Rent Value")
End Try
listing.props(i).CreationFlag = 1
listing.SaveProperties()
ShowProperties()
Return
End If
Next
MsgBox("You cannot create a new property." &
"You can only modify or replace an existing one.")
End If
ShowProperties()
End Sub
End Class
- In the Class Name combo box, select btnClose
- In the Method Name combo box. select Click
- Implement it as follows:
Private Sub btnCloseClick(ByVal sender As Object,
ByVal e As System.EventArgs) Handles btnClose.Click
End
End Sub
- Execute the application to see the result
- Create a few properties
- Close the application and execute it again
|
|