Creating Property Get/Let procedures for a private array - arrays

I am trying to assign a number of values to a private array in a class module using public Property Get/Let procedures. But when I try to get the values out, the array is showing as empty. Why is this?
Here's the relevant code:
Private pdt_RentStepDate(23) As Date
Public Property Get dt_RentStepDate(ByRef d1 As Integer) As Date
dt_RentStepDate(d1) = pdt_RentStepDate(d1)
End Property
Public Property Let dt_RentStepDate(ByRef d1 As Integer, something As Date)
pdt_RentStepDate(d1) = something
End Property

In your Property Get procedure, don't specify an index when you're assigning the return value:
Public Property Get dt_RentStepDate(ByRef d1 As Integer) As Date
' dt_RentStepDate(d1) = pdt_RentStepDate(d1) ' <-- WRONG
dt_RentStepDate = pdt_RentStepDate(d1) ' <-- RIGHT
End Property
If you specify an index, then instead of assigning the return value for the Property Get, you're actually calling the Property Let with the arguments d1 and pdt_RentStepDate(d1). (This has no effect because the Property Let ends up setting pdt_RentStepDate(d1) to itself.) Since no return value is assigned, the Property Get always returns an empty Date.

Related

How to declare variable for DataGridviewColumn Type?

This must be simple, but I couldn't figure it out even after reading Microsoft's specification.
How do I store DataGridViewColumn type in a declared variable? It has to provide a collection of types, similar to declaring variable for DataGridViewContentAlignment:
Dim GridAlignment as DataGridViewContentAlignment ' declare
GridAlignment = DataGridViewContentAlignment.MiddleCenter ' set
So it should be something like:
Dim GridColType1 as DataGridViewColumn ' declare variable (how?)
Dim GridColType2 as DataGridViewColumn ' declare variable (how?)
' To use variable like this:
GridColType1 = DataGridViewColumn.DataGridViewTextBoxColumn ' set it as TextBox column
GridColType2 = DataGridViewColumn.DataGridViewComboBoxColumn ' set it as ComboBox column
At this stage, no DataGridView exist, it's a definition to store for dynamic generation and I need the correct declaration in order to use it in PropertyGrid.
EDIT:
For another idea, here is what VS has in GUI when adding/editing DataGridView Column:
So it's the ColumnType declaration with the collection shown in the listbox, I'm looking for.
OK, it seems the best and easiest way is to define custom Enum.
Public Enum DataGridViewColumnType
NotSetError = 0
TextBoxColumn = 1
ImageColumn = 2
CheckBoxColumn = 3
ComboBoxColumn = 4
ButtonCOlumn = 5
End Enum
Then I can set a variable of that type:
Public GridColType As DataGridViewColumnType
Then it can be used in property:
<CategoryAttribute("Grid"), DefaultValueAttribute(""), DescriptionAttribute("Select column type"), DisplayName("Grid Column Type")>
Public Property PropGriColType() As DataGridViewColumnType
Get
Return GridColType
End Get
Set(ByVal Value As DataGridViewColumnType)
GridColType = Value
End Set
End Property
The result is then as desired:

Setting a string to be empty if value is null

I am not sure how to search for the issue I am trying to solve here. In the program I am writing (in VB.Net) I am trying to assign values pulled from a database to different variables in a structure.
Now my issue is that sometimes, some of the values pulled from the database are NULL, for example not every phone number has an extension. This is what I have for my code at the moment:
Structure CustomerContact
Public _name As String
Public _email As String
Public _fax As String
Public _phone1 As String
Public _phone2 As String
Public _phone3 As String
Public _ext1 As String
Public _ext2 As String
Public _ext3 As String
Public _type1 As String
Public _type2 As String
Public _type3 As String
End Structure
Dim contactData As DataTable = CustomerDBFunctions.GetCustomerContacts(Customer)
For Each row As DataRow In contactData.Rows
If contacts.Count < 1 Then
contacts.Add(New CustomerContact With {
._name = row.Item("FullName").ToString() & " (" & row.Item("ContactType").ToString() & ")",
._email = row.Item("Email").ToString(),
._fax = row.Item("Fax").ToString(),
._phone1 = row.Item("Phone").ToString(),
._ext1 = row.Item("Extension").ToString(),
._type1 = row.Item("PhoneType").ToString()})
End If
Next
Right now I am getting an error when the value in the database is NULL because it can't assign a NULL value to a string. I'd like to in the instances where a NULL value is present instead set the value of the variable to "" instead. I am just unsure how to code this.
Technically, the problem isn't that the column is null. String is a reference type, so it can but null (though, if it was null, you wouldn't be able to call ToString on it anyway). What's actually going on is that ADO.NET always returns DBNull.Value for all columns where the row contains a null value.
You could check it, like this:
If row.Item("Phone") <> DBNull.Value Then
customerContact._phone1 = row.Item("Phone")?.ToString()
End If
Note, I used ?. instead of . when calling ToString just in case the column actually is null rather than DbNull.Value. The reason for this is that I don't know what kind of code you're using to fill that DataTable. If it's ADO.NET that's filling it, it'll never be null, but if it's custom code that populates it via some other means, it might get actual nulls in it.
Since you are using a DataTable to return the value, it has a convenient IsNull method that you can use, which cleans up the code a little bit:
If Not row.IsNull("Phone") Then
customerContact._phone1 = row.Item("Phone")?.ToString()
End If
Obviously, if you're doing this a lot, it would be good to wrap it up into a reusable function. Also, if you want to shorten it up into one line, you could do so like this:
._phone1 = If(row.IsNull("Phone"), row.Item("Phone")?.ToString(), Nothing)
String concatenation can be used to convert Nothing to "" (other alternatives in my answer here)
._fax = row!Fax & "",

Fill public array with values

Basic arrays question:
I have declared a public array and initialized it with values. In another private sub, I want to fill that public array with values. What is the easiest way to do it?
The double variables in the array are also declared public. The following code is the array created and initialized in a public module. In the private sub, I am changing the values of the double variables (ch0LowLmt, ch1LowLmt, etc, etc) and now I just simply want to reinitialize the array with the new values. What is the simplest way to do it?
Public AlarmLowLimit() As Double = New Double(15) {Ch0LowLmt, Ch1LowLmt, Ch2LowLmt, Ch3LowLmt, Ch4LowLmt, Ch5LowLmt, Ch6LowLmt, Ch7LowLmt, Ch8LowLmt, Ch9LowLmt, _
Ch10LowLmt, Ch11LowLmt, Ch12LowLmt, Ch13LowLmt, Ch14LowLmt, Ch15LowLmt}
Because Double is a value type, you do need to change it manually in the way you are working.
Another way, is to encapsulate the double var inside a class, which can be put inside your array, so it will be a reference type.
In this case you'd just update your new reference type objects in the private function you have mentioned. They will also change in your array.
See a nice solution here.
And the code example in Vb.Net:
Public Class MyObjectWithADouble
Public Property Element() As Double
Get
Return m_Element
End Get
Set
m_Element = Value
End Set
End Property
Private m_Element As Double
' property is optional, but preferred.
End Class
Dim obj = New MyObjectWithADouble()
obj.Element = 5.0

Error message in a property

This is my problem. If a user type a number in the textbox is all right, but if he type a char, I don't see the messagebox () in the property.
Why ?
<TextBox HorizontalAlignment="Left"
TabIndex="12"
Text="{Binding Time_HH, UpdateSourceTrigger=PropertyChanged,StringFormat='{}{##}'}"
FlowDirection="RightToLeft"
MaxLength ="2"
Height="30"
Width="30" />
And this is the property
Private _Time_HH As Integer
Public Property Time_HH() As Integer
Get
Return _Time_HH
End Get
Set(value As Integer)
For i = 0 To Len(value.ToString)
If IsNumeric(value.ToString(i)) = False Then
MessageBox.Show("Error")
value = 0
End If
Next
_Time_HH = value
OnPropertyChanged("Time_HH")
End Set
End Property
Your Time_HH property is an Integer, there's no way it's gonna contain a non-numeric character.
At most, what will happen is that your Binding will fail due to the type mismatch (is your TextBox showing a red outline?)
If you wanna check if your user enters non-numeric characters, you have to use a type that allows so: a String.
Try this:
Private _Time_HH As Integer
Public Property Time_HH() As String
Get
Return _Time_HH.ToString()
End Get
Set(value As String)
For i = 0 To Len(value)
If IsNumeric(value.ToString(i)) = False Then
MessageBox.Show("Error")
value = 0
End If
Next
_Time_HH = Integer.Parse(value)
OnPropertyChanged("Time_HH")
End Set
End Property
If you need to use the numeric value, use the Integer field. You could create a second property of type Integer that simply exposes the field, if you want to use it for another Binding or something like that (remember to raise the OnPropertyChanged for that property too, then, on the Time_HH setter)
CAUTION - The code above will raise an Exception if the user types something like "00,01-2,0". IsNumeric returns True for all the characters in that String, but that doesn't mean it is a correct number.
In my opinion, it would be better to do this:
Private _Time_HH As Integer
Public Property Time_HH() As String
Get
Return _Time_HH.ToString()
End Get
Set(value As String)
Dim int As Integer
If Integer.TryParse(value, int) = False Then
MessageBox.Show("Error")
End If
_Time_HH = int
OnPropertyChanged("Time_HH")
End Set
End Property
Sorry if I did some mistakes, I usually code in C# and my VB is pretty rusty :P

ReadOnly Property Gets "Unintentional" Change

I understand that List, Array, Object etc. types "copied" by reference. However my natural and ordinary intend is to just have a "copy" of it in this context where I intentionally use ReadOnly instead of Read/Write property. In below sample the ReadOnly 'Extensions' property get change through 'm_extensions' reference change. Regardless, I think this behavior is incorrect and I have to do extra work to prevent ReadOnly properties from being overwritten. Is there any built in keyword to use for 'm_extensions' value protection?
Public Classs A
' more properties and methods here...
Private m_extensions() As String = {"*.abc", "*.def"}
Public ReadOnly Property Extensions() As String()
Get
Return m_extensions
End Get
End Property
End Class
Public Classs B
' more stuff here...
Private Function BuildFilter() As String
Dim l() As String = A.Extensions
Dim s As String = String.Empty
For m As Integer = 0 To l.Length - 1
Select Case l(m).ToLower
Case "*.*" : s = "All Files"
Case "*.abc" : s = "ABC File"
Case "*.def" : s = "DEF File"
Case Else : s = "XYZ File " + m.ToString
End Select
l(m) = String.Format("{1} ({0})|{0}", l(m), s)
Next
Return String.Join("|", l)
End Function
End Class
Readonly modifier means that anything using the property cannot change the reference that you protected this way (e.g. cannot set it to Nothing). It doesn't prevent changing the values in the array returned from that property.
One way around it could be to copy the array inside the property. This will prevent modifications of the original array:
Public ReadOnly Property Extensions() As String()
Get
Return m_extensions.Clone()
End Get
End Property

Resources