Overriding Sub to check if value is numeric - vb.net

I'm working on a problem with two user input controls, TextInput and NumericInput. TextInput accepts all characters, whereas NumericInput only accepts numeric inputs.
I'm aware that for my NumericInput Add Sub I will probably have to create a boolean to check if the input value is a number or not and then create an If statement using the boolean, however, I'm not sure how to go about this.
This is the code that I was able to come up with.
For my TextInput code I currently have the following:
Dim value As String 'current value'
Public Class TextInput
Public Overridable Sub Add(c As Char)
If value.length = 0 Then
value = Char.toString(c)
Else
value+=c
End If
End Sub
Public Function GetValue() As String
Return value
End Function
End Class
For my NumericInput code I currently have the following:
Public Class NumericInput
Inherits TextInput
Dim numericCheck As Boolean
Public Overrides Sub Add(c As Char)
If Not value.length = 0 Then
numericCheck = isNumeric(value)
End If
If numericCheck = True Then
value+=c
End If
End Sub
End Class
Output code is as follows:
Public Sub Main()
Dim input As TextInput = New NumericInput()
input.Add(CChar("1"))
input.Add(CChar("a"))
input.Add(CChar("0"))
Console.WriteLine(input.GetValue())
End Sub

First, the variable value should be encapsulated in TextInput class. You can declare it as protected so derived classes can access it. The value variable must have initial value otherwise value.Length raises an exception because it's null (Nothing).
Secondly, you can use IsNumeric function to check if a character is a number. Then call the base method of Add if it's a number.
Public Class TextInput
Protected value As String = "" 'current value'
Public Overridable Sub Add(c As Char)
If value.Length = 0 Then
value = Char.toString(c)
Else
value += c
End If
End Sub
Public Function GetValue() As String
Return value
End Function
End Class
Public Class NumericInput
Inherits TextInput
Public Overrides Sub Add(c As Char)
If IsNumeric(c) Then
MyBase.Add(c)
End If
End Sub
End Class

Related

How to hide expand button in a propertygrid in Windows Forms

I have written my on editor for a property in a propertyGrid. Everything works as expected, but for best user experience i want to hide the expand button on the propertygrid for this property. Can someone tell me how to do that?
I am using a custom typeconverter
Public Class PropertyLanguageSetupEditor
Inherits UITypeEditor
Public Overrides Function GetEditStyle(context As ITypeDescriptorContext) As UITypeEditorEditStyle
Return UITypeEditorEditStyle.Modal
End Function
Public Overrides Function EditValue(context As ITypeDescriptorContext, provider As IServiceProvider, value As Object) As Object
Try
Dim svc As IWindowsFormsEditorService = CType(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
Dim settings As LanguageSettings = value
Dim oldSettings As LanguageSettings = CType(value, LanguageSettings).Clone
If Not svc Is Nothing And Not settings Is Nothing Then
Dim form As New PropertyLanguageSetupWindow(settings)
If svc.ShowDialog(form) = DialogResult.OK Then
value = form.Data
Else
value = oldSettings
End If
End If
Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try
Return MyBase.EditValue(context, provider, value)
End Function
End Class
And this is de property which uses the typeConverter
<DisplayName("Properties Translation Settings"), Editor(GetType(PropertyLanguageSetupEditor), GetType(System.Drawing.Design.UITypeEditor)), TypeConverter(GetType(BrowsableTypeConverter)),
Description("Settings for the output text"), BrowsableTypeConverter.BrowsableLabelStyleAttribute(BrowsableTypeConverter.LabelStyle.lsEllipsis),
Category("10 - DXF Export"), Browsable(True)>
Public Property TranslationSettings As LanguageSettings = New LanguageSettings
My BrowsAbleTypeConverter
Public Class BrowsableTypeConverter
Inherits ExpandableObjectConverter
Public Enum LabelStyle
lsNormal
lsTypeName
lsEllipsis
lsText
End Enum
Public Class BrowsableLabelStyleAttribute
Inherits System.Attribute
Private eLabelStyle As LabelStyle = LabelStyle.lsEllipsis
Public Sub New(ByVal LabelStyle As LabelStyle)
eLabelStyle = LabelStyle
End Sub
Public Property LabelStyle() As LabelStyle
Get
Return eLabelStyle
End Get
Set(ByVal value As LabelStyle)
eLabelStyle = value
End Set
End Property
End Class
Public Class BrowsableLabelTextAttribute
Inherits System.Attribute
Private strText As String = ""
Public Sub New(ByVal value As String)
strText = value
End Sub
Public Property Text() As String
Get
Return strText
End Get
Set(ByVal value As String)
strText = value
End Set
End Property
End Class
Public Overrides Function CanConvertTo(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal destinationType As System.Type) As Boolean
Return True
End Function
Public Overrides Function ConvertTo(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal culture As System.Globalization.CultureInfo, ByVal value As Object, ByVal destinationType As System.Type) As Object
Dim Style As BrowsableLabelStyleAttribute = context.PropertyDescriptor.Attributes(GetType(BrowsableLabelStyleAttribute))
If Not Style Is Nothing Then
Select Case Style.LabelStyle
Case LabelStyle.lsNormal
Return MyBase.ConvertTo(context, culture, value, destinationType)
Case LabelStyle.lsTypeName
Return "(" & value.GetType.Name & ")"
Case LabelStyle.lsEllipsis
Return "(...)"
Case LabelStyle.lsText
Dim text As BrowsableLabelTextAttribute = context.PropertyDescriptor.Attributes(GetType(BrowsableLabelTextAttribute))
If text IsNot Nothing Then
Return text.Text
End If
End Select
End If
Return MyBase.ConvertTo(context, culture, value, destinationType)
End Function
End Class
Your TypeConverter derives from ExpandableObjectConverter, which means subproperties will be visible because of its GetPropertiesSupported method returning true.
In your TypeConverter, you simply need to override GetPropertiesSupported and return false.

How can I use textbox textchanged events to change user input classes?

InputValue1,..OperationAdd are instances of the class InputNumber. How do I assign my Inputvalues to the corresponding textboxes as option Strict On is activated?
Class MainWindow
Dim InputValue1 As New InputNumber
Dim InputValue2 As New InputNumber
Dim ExpectedResultValue As New InputNumber
Dim OperationAdd As New InputNumber
Private Sub TBoxNumber1_TextChanged(sender As Object, e As TextChangedEventArgs) Handles TBoxNumber1.TextChanged
TBoxNumber1.Text = InputValue1 'There is an error in this line, value of type InputNumber 'cannot be converted to a string
End Sub
Below is the InputNumber Class:
Public Class InputNumber
Inherits Input
Private _number As Integer
Public Property Number As Integer
Get
Return _number
End Get
Set(value As Integer)
_number = value
End Set
End Property
Protected Overrides Function Validate(s As String) As Boolean
Dim isValid As Boolean = Integer.TryParse(s, _number)
Return isValid
End Function
End Class
It seems to me that you should be getting the input from the TextBox into your InputNumber object, not the other way around. This:
TBoxNumber1.Text = InputValue1
should probably be this:
InputValue1.Validate(TBoxNumber1.Text)
When it actually comes time to display the value of that InputNumber, you would have to use InputValue1.Number.ToString(). Personally, I would add this to your InputNumber class:
Public Overrides Function ToString() As String
Return Number.ToString()
End Function
and then you can use InputValue1.ToString() instead.
EDIT:
It's been pointed out that the Validate method is Protected so it can't be called like that. Unless there's some use for it in the Input base class, I'm not sure what it's for because, as it stands, you'd need to validate externally anyway, e.g.
Dim number As Integer
If Integer.TryParse(TBoxNumber1.Text, number) Then
InputValue1.Number = number
End If
I am questioning the implementation of InputNumber. It does not make much sense in the current form. We don't know when validation is happen and Number is integer in fact.
I would do something like this.
Public Class InputNumber
Private _number As Integer
Private _hasNumber As Boolean
Public Sub New(s As String)
SetNumber(s)
End Sub
Public Sub New()
End Sub
Public ReadOnly Property Number As Integer
Get
Return _number
End Get
End Property
Public ReadOnly Property HasNumber As Boolean
Get
Return _hasNumber
End Get
End Property
Public Sub SetNumber(s As String)
_hasNumber = Integer.TryParse(s, _number)
End Sub
' For consistency...
Public Sub SetNumber(i As Integer)
_hasNumber = true
_number = i
End Sub
Public Overrides Function ToString() As String
If HasNumber Then Return Number.ToString()
Return String.Empty
End Function
End Class
Then your usage will be (and I agree with #jmcilhinney, when you have TextChange event, you want to take a value from the text box and set a variable)
Dim inp As New InputNumber("ddd")
txtBox1.Text = If(inp.HasNumber, inp.Number.ToString(), "NO VALUE") '' example to use HasNumber
inp.SetNumber("sss")
txtBox2.Text = inp.ToString() '' Example to use straight value
inp.SetNumber(10)
Dim current As Integer = If(inp.HasNumber, inp.Number, -1) '' using as numeric value
Now, this class makes slightly more sense

Comparing list of class by string length and text comparison

I have a List(Of Abbreviation).
The class "Abbreviation" contains the string members "Input", "Output" and "CaseSensitive".
The class is stated below.
I would like to sort this list so that the class with the "Input"
"ZZZ"
comes before
"zz"
The comparison should thus first compare by string length, then by alphetical order, and then by CaseSensitive.
How could I sort the list this way?
Public Class Abbreviation
Implements IComparable
Private _sIn As String = String.Empty
Private _sOut As String = String.Empty
Private _bCaseSensitive As Boolean = False
Public Property Input() As String
Get
Return _sIn
End Get
Set(value As String)
_sIn = value
End Set
End Property
Public Property Output() As String
Get
Return _sOut
End Get
Set(value As String)
_sOut = value
End Set
End Property
Public Property CaseSensitive() As Boolean
Get
Return _bCaseSensitive
End Get
Set(value As Boolean)
_bCaseSensitive = value
End Set
End Property
Public Sub New(ByVal uInput As String, ByVal uOutput As String, ByVal uCaseSensitive As Boolean)
_sIn = uInput
_sOut = uOutput
_bCaseSensitive = uCaseSensitive
End Sub
End Class
First, you can simplify your code by using automatic properties. The compiler writes the get, set, and backer fields (the private fields). This is the preferred way in recent versions of Visual Studio if there is no extra code in the getter, setter.
Another small detail with your Sub New. It violates encapsulation to set the private fields directly. Always go through the Public Properties. There could be code in the setter that needs to run before storing the data in the private fields. Classes like to keep their data close to the vest in their private fields.
Example of Auto Implemented Properties
Public Property Input As String
Public Property Output As String
Public Property CaseSensitive As Boolean
The sort can be done in one line of code using a Linq query.
Dim orderedList = From abrev In lstAbreviations Order By abrev.Input.Lenght Descending Select abrev
To check the output...
For Each abrev As Player In orderedList
Debug.Print(abrev.Input)
Next
I think I got it, except the case sensitivity. CaseSensitive should come before CaseSensitive = False.
Public Class Abbreviation
Implements IComparable(Of Abbreviation)
Private _sIn As String = String.Empty
Private _sOut As String = String.Empty
Private _bCaseSensitive As Boolean = False
Public Function CompareTo(uOther As Abbreviation) As Integer _
Implements IComparable(Of Abbreviation).CompareTo
If uOther.Input.Length > Me.Input.Length Then
Return 1
ElseIf uOther.Input.Length < Me.Input.Length Then
Return -1
Else
If uOther.Input > Me.Input Then
Return 1
Else
Return -1
End If
End If
End Function

How to make Arrays of Object in VB.net?

I am unable to debug this.
Is my procedure of array-making wrong?
The error it shows is
System.NullReferenceException :'Object reference not set to an instance of an object'
Module Module1
Class Toy
Private Name, ID As String
Private Price As Single
Private MinimumAge As Integer
Dim Count As Integer
Public Sub New()
End Sub
Public Sub SetName(ByVal N As String)
Name = N
End Sub
Public Sub SetID(ByVal I As String)
'VALIDATION CHECK FOR ID !
While Len(I) < 4
Console.WriteLine("Kindly Enter the ID with Lenght of Max 4 Characters")
End While
ID = I
End Sub
Public Sub SetPrice(ByVal SP As Single)
Price = SP
End Sub
Public Sub SetUserAge(ByVal SM As Integer)
'VALIDATION CHECK FOR AGE
While SM < 0 Or SM < 18
Console.WriteLine("Minimum age is 18")
End While
MinimumAge = SM
End Sub
Public Function GetName()
Return Name(Count)
End Function
Public Function GetID()
Return ID
End Function
Public Function GetPrice()
Return Price
End Function
Public Function GetAge()
Return MinimumAge
End Function
End Class
Class ComputerGame
Inherits Toy
Private Category, Consol As String
Public Sub New()
End Sub
Public Sub SetConsole(ByVal C As String)
While C <> "PS4" Or C <> "XBOX"
Console.WriteLine("Invalid console entered")
End While
Consol = C
End Sub
Public Sub SetCategory(ByVal SC As String)
Category = SC
End Sub
Public Function GetConsole()
Return Consol
End Function
Public Function GetCategory()
Return Category
End Function
End Class
Class Vehicle
Inherits Toy
Private Type As String
Private Length, Height, Weight As Single
Public Sub New()
End Sub
Public Sub SetType(ByVal TY As String)
While TY <> "Car" Or TY <> "Bus" Or TY <> "Truck"
Console.WriteLine("vehicle is not in list !")
End While
Type = TY
End Sub
Public Sub SetLength(ByVal SL As Single)
Length = SL
End Sub
Public Sub SetHeight(ByVal SH As Single)
Height = SH
End Sub
Public Sub SetWeight(ByVal SW As Integer)
Weight = SW
End Sub
Public Function GetT()
Return Type
End Function
Public Function GetLength()
Return Length
End Function
Public Function GetHeight()
Return Height
End Function
Public Function GetWeight()
Return Weight
End Function
End Class
Sub Main()
Dim ThisGame(6) As Toy
ThisGame(6) = New Toy
ThisGame(1).SetID("23456a")
ThisGame(2).SetID("236789b")
Console.WriteLine(ThisGame(1).GetID)
Console.ReadKey()
End Sub
End Module
This is what your Toy class should look like using the long method of Properties. Notice that you have Public Properties and a private field to store the values (sometimes called a backer field) Each Property has a Get and a Set procedure where you can add your validation code.
Public Class Toy
Private _Name As String
Public Property Name As String
Get
Return _Name
End Get
Set(value As String)
_Name = value
End Set
End Property
Private _ID As String
Public Property ID As String
Get
Return _ID
End Get
Set(value As String)
If value.Length < 4 Then
Console.WriteLine("Kindly Enter the ID with Lenght of Max 4 Characters")
Exit Property
End If
_ID = value
End Set
End Property
Private _Price As Single
Public Property Price As Single
Get
Return _Price
End Get
Set(value As Single)
_Price = value
End Set
End Property
Private _MinimumAge As Integer
Public Property MinimumAge As Integer
Get
Return _MinimumAge
End Get
Set(value As Integer)
If value < 0 Or value < 18 Then
Console.WriteLine("Minimum age is 18")
Exit Property
End If
_MinimumAge = value
End Set
End Property
Private _Count As Integer
Public Property Count As Integer
Get
Return _Count
End Get
Set(value As Integer)
_Count = value
End Set
End Property
End Class
Current versions have Automatic Properties where the compiler provides the getter, setter, and backer fields. Notice that you can still write your own Get and Set where you need to add code.
Public Class Toy
Public Property Name As String
Public Property Price As Single
Public Property Count As Integer
Private _ID As String
Public Property ID As String
Get
Return _ID
End Get
Set(value As String)
If value.Length < 4 Then
Console.WriteLine("Kindly Enter the ID with Lenght of Max 4 Characters")
Exit Property
End If
_ID = value
End Set
End Property
Private _MinimumAge As Integer
Public Property MinimumAge As Integer
Get
Return _MinimumAge
End Get
Set(value As Integer)
If value < 0 Or value < 18 Then
Console.WriteLine("Minimum age is 18")
Exit Property
End If
_MinimumAge = value
End Set
End Property
End Class
Please read the in line comments in regards to your array.
Sub Main()
Dim ThisGame(6) As Toy 'You are defining and array with 7 elements of Toy
'Each element is Nothing at this point and you will get a null exception error if you
'try to access an element.
ThisGame(6) = New Toy 'Here you have created an instance of your class for the 7th element
'The other six elements are still nothing so the next 3 lines will get
'NullReferenceException: 'Object reference not set to an instance of an object.'
'ThisGame(1).ID = "23456a"
'ThisGame(2).ID = "236789b"
ThisGame(1) = New Toy
ThisGame(1).ID = "23456a"
ThisGame(2) = New Toy
ThisGame(2).ID = "236789b"
'Remember the first element in you array is ThisGame(0)
Console.WriteLine(ThisGame(1).ID)
Console.ReadKey()
End Sub

VB .Net - ShouldSerialize function

I have a problem with ShouldSerialize function.
I defined an usercontrol with a label (named Label1) on it.
Now i put the code below in the usercontrol class :
Imports System.ComponentModel
Public Class UserControl1
Dim _Range As UShort = 100
Private Sub UserControl1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = _Range
End Sub
Public Function ShouldSerializeTBValueRange() As Boolean
Return _Range <> 200
End Function
Public Sub ResetTBValueRange()
_Range = 200
Label1.Text = _Range
End Sub
Public Property TBValueRange As UShort
Get
Return _Range
End Get
Set(ByVal Steps As UShort)
_Range = Steps
Label1.Text = _Range
End Set
End Property
End Class
Now in a new form include the usercontrol.
In the properties grid of the usercontrol u can find the property TBValueRange.
If you right click in the property name you can Reinit the property.
After reinit u can see value 200 in the property.
Now, regenerate the project will reset the property to the initial value (id 100).
Why the value 200 didn't stay?
If i replace the line Return _Range <> 200 in the function ShouldSerializeTBValueRange() by
Return Not _Range.Equals(200)
it will work.
i don't understand.
Anyone could explain this?
The methods are working as coded. The thing which seems to not work as expected is the Not _Range.Equals(200) portion.
You initialize _Range to 100: Dim _Range As UShort = 100
Then, your ShouldSerializeTBValueRange method tells VS to only save the range value when it is not 200: Return _Range <> 200
So, when you reset it to 200 in the IDE, it wont save a value of 200, and the initial value of 100 displays.
The code uses one value for the default, 100 but use a different value for ShouldSerialize test. You should either change it to use a default of 200:
Dim _Range As UShort = 200
Or change the ShouldSerialize test to use 100:
Public Function ShouldSerializeTBValueRange() As Boolean
Return _Range <> 100
End Function
Treating the default value as the default, and using only one value for the default everything works as expected using just ShouldSerializexxx and Resetxxx with no need for anything else.
' THIS is the default value -
' ie the value that need not be saved because the
' control automatically starts with that value
Dim _Range As UShort = 200US
' Controls:
' - displays the prop value in Bold in the property window
' when the value is NOT the default
' - saves the value when it is NOT the default
' - enables/disables the RESET function
Public Function ShouldSerializeTBValueRange() As Boolean
Return (_Range <> 200US)
End Function
Using one value for the actual default (100) and then returning T/F based on a different value (200) results in
100 being saved when it need not be
200 not being saved when it should be
the Reset menu item and Bold value being in the incorrect state
The oddity is that Not _Range.Equals(200) seems to fail. It returns False after a reset (to 200) which causes the value to be saved when it really should not. There are 2 overloads for this:
UInt16.Equals(obj As Object) As Boolean
UInt16.Equals(v As UShort) As Boolean
If you pass anything other than an actual UInt16/UShort, the value will be boxed as Object. So, Not _Range.Equals(200) is using the first because 200 is Int32. The ILCode for that version is:
public override bool Equals(object obj)
{
return obj is ushort && this == (ushort)obj;
}
The test will fail the first test because obj contains an Int32. If you pass a UShort, it will work:
UShort.Equals(_Range, 200US)
'or:
_Range.Equals(200US)
All good reasons to understand the different data types, avoid boxing (As Object) and always and forever set Option Strict On.
Thanks you all to have spent time on my question.
I found my answer : when ShouldSerialize function return false the property value isn't save in the file Form1.designer.vb, so it gets the original value.
For my needed the ShouldSerialize function should always return true.
Public Function ShouldSerializeTBValueRange() As Boolean
Return true
End Function
So the property value will always be saved.
Now, what i'm looking for is how to control the context menu of the property grid.
I want the option "Reinit" greyed when the value is good.
Finally, i found something, with the use of PropertyDescriptor.
For whose are interested, we can save properties in the designer.vb file and test the value to reset.
here is my program, based on the article from MSDN - Microsft:
Imports System.ComponentModel
Imports System.Windows.Forms.Design
<Designer(GetType(DemoControlDesigner))>
Public Class UserControl1
Dim _MyProperty1 As String = "Test1"
Dim _MyProperty2 As Integer = 100
Dim _MyProperty3 As UShort = 200
Public Sub New()
InitializeComponent()
End Sub
Public Function CanResetMyProperty1() As Boolean
Return _MyProperty1 <> "Test"
End Function
Public Sub ResetMyProperty1()
_MyProperty1 = "Test"
End Sub
Public Property MyProperty1 As String
Get
Return _MyProperty1
End Get
Set(ByVal Value As String)
_MyProperty1 = Value
End Set
End Property
Public Function CanResetMyProperty2() As Boolean
Return _MyProperty2 <> 150
End Function
Public Sub ResetMyProperty2()
_MyProperty2 = 150
End Sub
Public Property MyProperty2 As Integer
Get
Return _MyProperty2
End Get
Set(ByVal Value As Integer)
_MyProperty2 = Value
End Set
End Property
Public Function CanResetMyProperty3() As Boolean
Return _MyProperty3 <> _MyProperty2
End Function
Public Sub ResetMyProperty3()
_MyProperty3 = _MyProperty2
End Sub
Public Property MyProperty3 As UShort
Get
Return _MyProperty3
End Get
Set(ByVal Value As UShort)
_MyProperty3 = Value
End Set
End Property
End Class
Friend NotInheritable Class SerializePropertyDescriptor
Inherits PropertyDescriptor
Private _pd As PropertyDescriptor = Nothing
Public Sub New(ByVal pd As PropertyDescriptor)
MyBase.New(pd)
_pd = pd
End Sub
Public Overrides ReadOnly Property Attributes() As AttributeCollection
Get
Return Me._pd.Attributes
End Get
End Property
Protected Overrides Sub FillAttributes(ByVal attributeList As IList)
MyBase.FillAttributes(attributeList)
End Sub
Public Overrides ReadOnly Property ComponentType() As Type
Get
Return Me._pd.ComponentType
End Get
End Property
Public Overrides ReadOnly Property Converter() As TypeConverter
Get
Return Me._pd.Converter
End Get
End Property
Public Overrides Function GetEditor(ByVal editorBaseType As Type) As Object
Return Me._pd.GetEditor(editorBaseType)
End Function
Public Overrides ReadOnly Property IsReadOnly() As Boolean
Get
Return Me._pd.IsReadOnly
End Get
End Property
Public Overrides ReadOnly Property PropertyType() As Type
Get
Return Me._pd.PropertyType
End Get
End Property
Public Overrides Function CanResetValue(ByVal component As Object) As Boolean
Try
Return CallByName(component, "CanReset" & _pd.Name, CallType.Get, Nothing)
Catch ex As Exception
MsgBox(ex.Message)
End Try
Return False
End Function
Public Overrides Function GetValue(ByVal component As Object) As Object
Return Me._pd.GetValue(component)
End Function
Public Overrides Sub ResetValue(ByVal component As Object)
Me._pd.ResetValue(component)
End Sub
Public Overrides Sub SetValue(ByVal component As Object, ByVal val As Object)
Me._pd.SetValue(component, val)
End Sub
Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
Return True
End Function
End Class
Class DemoControlDesigner
Inherits ControlDesigner
Dim PropertiesToSerialize As String() = {"MyProperty1", "MyProperty2", "MyProperty3"}
Protected Overrides Sub PostFilterProperties(ByVal properties As IDictionary)
Dim original As PropertyDescriptor
For Each PropName As String In PropertiesToSerialize
If properties.Contains(PropName) Then
original = properties(PropName)
properties(PropName) = New SerializePropertyDescriptor(original)
End If
Next
MyBase.PostFilterProperties(properties)
End Sub
End Class
For each property that should be serialized and tested for reset, we should write a sub "CanResetPropertyName" which test the value to reset (see sample).
And the values stay now, even if we regenerate the project.
It's working fine for me, maybe it can be improved.
Regards.