Function Returns Byref - vb.net

Can a function return a value byref instead of the default byval? That is to say, allow me to directly edit the variable that it is retrieving instead of just giving me a copy of that variable.
Right now I'm trying to write a function that will return, based on what the user has selected through a combobox, a particular setting (eg. My.Settings.somethingHere). I then want to be able to edit the setting directly through just calling the function. Is that at all possible?
private function myFunction() as byte
select case comboBox1.text
case "a"
return my.settings.a
case "b"
return my.settings.b
end select
end function
private sub something()
myFunction() -= 1
end sub

Function can't return reference of byte instead you may create property (Writable) to assign value.
Public WriteOnly Property Change As SByte
Set(value As SByte)
Select Case comboBox1.text
Case "a"
My.Settings.a = value
Case "b"
My.Settings.b = value
End Select
End Set
End Property
and assign value to Change property,
private sub something()
Change -= 1
end sub

Related

Recursive value in a function

I am trying to develop a simple class-based function that will modify a previous value determined by the function, that is, it is a recurrence relationship.
In essence, I am developing my own random number generator which will work the same way the current Random class works, i.e.
Dim ran as New Random(123456)
For i = 0 To 9
MessageBox.Show(ran.NextDouble & " " & ran.Next(1,11))
Next
I can successfully do this using a class-based method simply by sending a value ByRef, but as you know for a method call, the old value to be modified needs to be placed inside the call to the method. Thus, I am trying to overcome use of a method or a global typed variable, and rather would like the instantiated class to somehow remember what the current value is.
The example code below attempts to multiply the value _value by 2 during every function call, so the expected result would be 2, 4, 8, 16, etc. However, even though a 2 is initially sent to the constructor, the value of _value is always returned as zero.
Class Example
Public _value As Integer
Public Sub New(ByVal _value)
End Sub
Public Function Value() As Integer
_value *= 2
End Function
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim x As New Example(2)
For i = 0 To 9
MessageBox.Show(x.Value)
Next
End Sub
Normally fields are Private. If you want to expose data from your class you would use a Public Property.
Change the name of the parameter for Sub New. If properly qualified your name will work but it is confusing. You must do something with the passed in value! Assign it to your field _value.
Your Function has no return value. It simply changes the value of _value. If you don't return anything use a Sub. Change the name of your Function to something meaningful. Add a Return statement to send a value back to the calling code.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim x As New Example(2)
For i = 0 To 9
MessageBox.Show(x.DoubleValue.ToString)
Next
End Sub
Class Example
Private _value As Integer
Public Sub New(ByVal Input As Integer)
_value = Input
End Sub
Public Function DoubleValue() As Integer
_value *= 2
Return _value
End Function
End Class

Overriding Sub to check if value is numeric

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

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.

Datagridview bound to object - Making the new rows appear blank

I have a Datagridview that changes its content according to a selection the user makes in a listBox.
The DGV consits of 2 comboboxes (Country, Product) and 1 textbox (Quantity).
I've created a class combined of 3 integers.
This class is used as a type of list, which is the datasource for the DGV.
There is also another list containing the prior list, so I have a list of datasources.
The DGV's datasource is a BindingSource that changes whenever the SelectedIndex of the listBox is fired.
My problem occurs whenever a new row is added to the DGV:
I use the BindingSource.AddNew which calls the constructor of the class, but it must assign values to each item in the class. That way, whenever I click any cell in the DGV I don't get a blank row.
Moreover, when the BS changes and then returned, another row is added.
What I want to get is a blank row - empty comboboxes and textbox.
Thanks for your help!
The class:
Public Class PoList
Private _CountryID As Integer
Private _ProductID As Integer
Private _Quantity As Integer
Public Sub New(ByVal CountryID As Integer, ByVal ProductID As Integer, ByVal Quantity As Integer)
_CountryID = CountryID
_ProductID = ProductID
_Quantity = Quantity
End Sub
Private Sub New()
_CountryID = 1
_ProductID = 2
_Quantity = Nothing
End Sub
Public Property CountryID() As Integer
Get
Return _CountryID
End Get
Set(ByVal value As Integer)
_CountryID = value
End Set
End Property
Public Property ProductID() As Integer
Get
Return _ProductID
End Get
Set(ByVal value As Integer)
_ProductID = value
End Set
End Property
Public Property Quantity() As Integer
Get
Return _Quantity
End Get
Set(ByVal value As Integer)
_Quantity = value
End Set
End Property
Public Shared Function CreateNewPoList() As PoList
Return New PoList
End Function
End Class
Private Sub List_AddRow(ByVal sender As Object, ByVal e As AddingNewEventArgs) Handles AllListBindingSource.AddingNew
e.NewObject = PoList.CreateNewPoList
End Sub
Creating a new inner list:
AllList.Add(New List(Of PoList))
AllListBindingSource.AddNew()
AllListBindingSource.DataSource = AllList(TableCounter)
AddPoDetails.DataSource = AllListBindingSource
SelectedIndexChanged event:
AllListBindingSource.DataSource = AllList(AddPoList.SelectedIndex)
AddPoDetails.DataSource = Nothing
AddPoDetails.DataSource = AllListBindingSource
Right, lets see if I can help you.
As I interpret it you have a list filled with lists. These lists don't know their own identity and is based on the current index in the list.
First of I wouldn't use Bindingsource.AddNew I would add the new object straight to the list instead.
AllList(TableCounter).Add(New Polist())
This way you know exactly how many objects has been created, by using events you aren't quite sure are you.
To refresh the list do this:
AllListBindingSource.ResetBindings(true)
Which will update your DGV with the new line.
Now you need to restructure your class since when you create a new Polist you set a value to nothing. This will crash your table. What you need to do is this:
Private _Quantity As String
Public Property Quantity() As String
Get
Return _Quantity
End Get
Set(ByVal value As String)
_Quantity = value
End Set
End Property
Using a string is the only way for you to get a blank textbox, I would recommend you to have 0 as default if you are using Quantity as an integer (which you should). Your constructor needs to be changed to this:
Private Sub New()
_CountryID = 0
_ProductID = 0
_Quantity = ""
End Sub
In your combobox columns you have to add a blank item in the top (I'm guessing your adding them manually), should be possible by having a blank row in the top of the items.

Storing a value for each ComboBox item

In lack of a Value property I planned to use Classes for storing Text and Value properties for my ComboBox items. So far I've succeeded.
Here is my class:
Public Class clCombobox
Public cname As String
Public cvalue As Integer
Public Property Display() As String
Get
Return Me.cname
End Get
Set(ByVal value As String)
Me.cname = value
End Set
End Property
Public Property Value() As String
Get
Return Me.cvalue
End Get
Set(ByVal value As String)
Me.cvalue = value
End Set
End Property
Public Sub New(ByVal name As String, ByVal value As String)
cname = name
cvalue = value
End Sub
Public Overrides Function ToString() As String
Return cname
End Function
End Class
Data is being added to the ComboBox like this:
cmbComboxBox.Items.Add(New clCombobox("Text", 1))
It seems like this works so far. But how do I get data back. Like if I want the value of the selected CheckBox item?
I tried using:
CType(cmbCombobox.SelectedItem, clCombobox).Value()
Did not work.
As per the documentation, use the SelectedItem property to retrieve the object that you stored in it.
Code to retrieve value you want:
Dim selectedItem as clCombobox = CType(cmbComboBox.SelectedItem, clCombobox)
Dim value As Integer = selectedItem.cvalue