Calling Private Functions from combobox - vb.net

I need to build an application that could run code in private function, based on what user has selected using combobox.
For example combo box has three values, One, Two, Three
If user selects one, code written under Private Function One() runs and vise versa
Thanks
Furqan

An easier way would be to assign a function for when the combo box is selected. Inside your function have a select statement like: (Pesduo)
Function comboSelected
Case "One"
call Onefunction()
Case "Two"
call Twofunction()
End function

Why are you declaring these as private?
Form controls cannot access private functions. You should declare them as protected.

Here's a way to make it work - assuming Windows Forms.
First, define this class:
Public Class ComboAction
Public Sub New(ByVal text As String, ByVal action As Action)
_text = text
_action = action
End Sub
Private _text As String
Public ReadOnly Property Text() As String
Get
Return _text
End Get
End Property
Private _action As Action
Public ReadOnly Property Action() As Action
Get
Return _action
End Get
End Property
Public Overrides Function ToString() As String
Return Me.Text
End Function
End Class
Now create a form like this:
Public Class ComboActionForm
Private Sub ComboActionForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.ComboBox1.Items.Add(New ComboAction("Show Foo", AddressOf Foo))
Me.ComboBox1.Items.Add(New ComboAction("Show Bar", AddressOf Bar))
End Sub
Private Sub Foo()
System.Windows.Forms.MessageBox.Show("Foo")
End Sub
Private Sub Bar()
System.Windows.Forms.MessageBox.Show("Bar")
End Sub
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
CType(Me.ComboBox1.SelectedItem, ComboAction).Action.Invoke()
End Sub
End Class
You can add as many ComboAction classes to the ComboBox as you wish. Each can have any Action you define - private methods or otherwise. The sky is the limit. :-)

See my another post. This works great!

Related

VB - Find child form from parent

I am in a project with multiple form.
I create a TicTacToe form here :
Private Sub MenuTicTacToe(ByVal sender As Object, ByVal e As System.EventArgs)
Dim page As Form = New TicTacToe
page.Show(Me)
End Sub
Here is a TicTacToe form:
Public Class TicTacToe
Public opponent as String
'Some code where user set opponent
Public Function Receive(S As String)
if string = opponent
'Some code
End Function
End Class
I would like to call my function Receive in my main form
If i do:
TicTactoe.Receive(S)
It call a instance of Receive where opponent does not exist.
I would like to find the oppened form of TicTacToe and call Receive
Thanks
Comments in line
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
page.Receive("Joe")
End Sub
'A form level variable to hold a reference to the instance of TicTacToe
'Although vb.net can use default instances, you have created an explicit
'instance of TicTacToe so you need to keep a reference if you want to
'refer to this instance.
Private page As TicTacToe
Private Sub MenuTicTacToe(ByVal sender As Object, ByVal e As System.EventArgs)
page = New TicTacToe()
page.Show(Me)
End Sub
Partial Public Class TicTacToe
Inherits Form
Public opponent As String
'Functions must be declared as a Type
'If you do not need a return value use a Sub
Public Function Receive(S As String) As String
Dim someString As String = ""
If S = opponent Then
'Do something
End If
'There must be a return Value
Return someString
End Function
End Class
Use this to show the form
Dim page As TicTacToe
Private Sub MenuTicTacToe(ByVal sender As Object, ByVal e As System.EventArgs)
page = New TicTacToe
page.Show(Me)
End Sub
Then you can use
page.Receive(S)
Edit
To use multiple forms
For Each f As TicTacToe in Application.OpenForms().OfType(Of TicTacToe)
f.Receive (S)
Next
In C#, you'd need a new instance, but as you are in VB, the compiler already does that for you.
What you are currently doing, is creating a new instance of the TicTacToe form and showing it:
Private Sub MenuTicTacToe(ByVal sender As Object, ByVal e As System.EventArgs)
Dim page As Form = New TicTacToe
page.Show(Me)
End Sub
But you don't save that instance anywhere. Then, in your next piece of code, you are using a different instance, which is the static one created by the compiler:
TicTacToe.Receive(S) // TicTacToe is the static instance
Therefore, you end up calling two different instances, which explains why there is no opponent set.
To get around this problem, do not create a new instance. In your Private Sub MenuTicTacToe, just use the instance created by the compiler, and you won't have this problem, just like this:
Private Sub MenuTicTacToe(ByVal sender As Object, ByVal e As System.EventArgs)
TicTacToe.Show(Me)
End Sub
Hope this helps.

Can't Remove Listview Item From Second Form

I am having an issue when trying to delete ListView Items from a second form.
For example, if I use the following command on Form1 it works:
Listview1.SelectedItems(0).Remove
However, if I attempt to remove from Form2 like so:
Form1.Listview1.SelectedItems(0).Remove
I get the following error:
"Invalid argument=value of '0' is not valid for 'index'. Parameter name: index"
I then tried to get a count of items from the listview on Form2 and it gives me a return of 0
Form1.Listview1.Items.Count
I'm not sure what my problem is.
Update
I have posted a brief example of my code (using your suggestion as I can understand it):
frmShowMessages
Private Sub ViewMessage()
Dim frm As New frmViewMailMessage
frm.Show()
End Sub
Public Sub DeleteItem(ByVal index As Integer)
lsvReceivedMessages.Items(index).Remove()
End Sub
frmViewMessage
Private instanceForm as frmShowMessages
Private Sub frmViewMailMessage_Load(sender As Object, e As EventArgs) Handles MyBase.Load
instanceForm = New frmShowMessages()
End Sub
Private Sub cmdDelete_Click(sender As Object, e As EventArgs) Handles cmdDelete.Click
instanceForm.DeleteItem(_index)
End Sub
Hopefully my code can help identify where my issue is.
In VB.net usually you get a default Form instance for each of your Form. Probably you are creating an instance of Form1 and then you are trying to access ListView1 of default instance.
E.g.
Sub ButtonClick()
Dim f As New Form1()
f.Show()
' at this point if you access f's ListView you will get correct count
f.ListView1.Items.Count
' however if you try to access default instance it will NOT have any item
Form1.ListView.Items.Count
End Sub
It means your instance f is NOT equal to default Form1 instance.
Solution can be, make the f variable as class level variable and use it everywhere. Or if Form1 will have only 1 instance, then you can use the default instance everywhere.
Personally I would NOT go with direct control accessing over forms. I would create a Public method which should return the data as list to the caller, in this case your Form2.
UPDATED-2:
As per your given scenario, I am simplifying things for you, and doing implementation using Event.
Public Class frmShowMessages
Private Sub btnOpenMessage_Click(sender As System.Object, e As System.EventArgs) Handles btnOpenMessage.Click
Dim frmView As New frmViewMessage(Me.ListView1.SelectedItems(0).Index)
AddHandler frmView.MessageDeleted, AddressOf DeleteMessageHandler
frmView.Show()
End Sub
Private Sub DeleteMessageHandler(sender As Object, e As frmViewMessage.MessageDeletedEventArgs)
Me.ListView1.Items.RemoveAt(e.MessageIndex)
End Sub
End Class
Public Class frmViewMessage
' a class which will be used for Event communication
Public Class MessageDeletedEventArgs
Inherits EventArgs
Public Property MessageIndex As Integer
Public Sub New(ByVal iIndex As Integer)
MyBase.New()
Me.MessageIndex = iIndex
End Sub
End Class
' main event which will alert the parent that a message deletion should be done
Public Event MessageDeleted As EventHandler(Of MessageDeletedEventArgs)
' private variable that will hold the MessageIndex
Private Property MessageIndex As Integer
' method that is responsible to raise event
Protected Overridable Sub OnMessageDeleted()
RaiseEvent MessageDeleted(Me, New MessageDeletedEventArgs(Me.MessageIndex))
End Sub
' we want to create this Form using the MessageIndex of ListView
Public Sub New(ByVal iMessageIndex As Integer)
Me.InitializeComponent()
Me.MessageIndex = iMessageIndex
End Sub
' the delete button will raise the event to indicate parent that
' a deletion of message should be done
Private Sub btnDelete_Click(sender As System.Object, e As System.EventArgs) Handles btnDelete.Click
Me.OnMessageDeleted()
End Sub
End Class

Access control in masterpage from shared function of same masterpage

I'm calling a shared function of a masterpage from a content page. In that shared function I want to access a control in the masterpage, but I don't know how.
main.master
<asp:Literal ID="ltCurrency" runat="server" />
main.master.vb
Partial Public Class main
Inherits System.Web.UI.MasterPage
Public Property CurrencyText() As String
Get
Return ltCurrency.Text
End Get
Set(ByVal value As String)
If value <> "" Then
ltCurrency.Text = value
End If
End Set
End Property
Public Shared Function DoSomething() As String
ltCurrency.Text="SOME TEXT" 'throws error: Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class.
CurrencyText="SOME TEXT" 'this property isn't found at all
'I also tried instantiating a new class of the current masterpage:
Ctype(main,Masterpage).CurrencyText
End Function
End Class
From page1.aspx I call:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
main.DoSomething()
End Sub
What else can I do?
For what it's worth (I don't know why you need to make it shared), you can use HttpContext to get the reference to your page and from there to your master:
Public Shared Function DoSomething() As String
Dim myPage = TryCast(HttpContext.Current.Handler, Page)
If myPage IsNot Nothing Then
Dim myMaster As main = TryCast(myPage.Master, main)
If myMaster IsNot Nothing Then
myMaster.ltCurrency.Text = "SOME TEXT"
myMaster.CurrencyText = "SOME TEXT"
End If
End If
End Function
Step1: Create an event in your content page.
Public Event DoSomething(sender as object, myString as String)
Step2: On your mainpage add an eventhandler to the event that you just created in your content page.
Addhandler contentPage.DoSomething, AddressOf ChangeCurrentText
Step3: In the handler do whatever you would like to do.
Private Sub ChangeCurrentText(sender, text)
ltCurrency.Text = text
End Sub
Step4: Raise the event in the content page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
RaiseEvent DoSomething(ME, "BLAH BLAH")
End Sub

AddressOf with parameter

One way or another I need to link groupID (and one other integer) to the button I am dynamically adding.. any ideas?
What I can do;
AddHandler mybutton.Click, AddressOf PrintMessage
Private Sub PrintMessage(ByVal sender As System.Object, ByVal e As System.EventArgs)
MessageBox.Show("Dynamic event happened!")
End Sub
What I can't do, but want to;
AddHandler mybutton.Click, AddressOf PrintMessage(groupID)
Private Sub PrintMessage(ByVal groupID as Integer)
MessageBox.Show("Dynamic event happened!" & groupID .tostring)
End Sub
There is no way to do this with AddressOf itself. What you're looking for is a lambda expression.
AddHandler myButton.Click, Function(sender, e) PrintMessage(groupId)
Private Sub PrintMessage(ByVal groupID as Integer)
MessageBox.Show("Dynamic event happened!" & groupID .tostring)
End Sub
You can create your own button class and add anything you want to it
Public Class MyButton
Inherits Button
Private _groupID As Integer
Public Property GroupID() As Integer
Get
Return _groupID
End Get
Set(ByVal value As Integer)
_groupID = value
End Set
End Property
Private _anotherInteger As Integer
Public Property AnotherInteger() As Integer
Get
Return _anotherInteger
End Get
Set(ByVal value As Integer)
_anotherInteger = value
End Set
End Property
End Class
Since VB 2010 you can simply write
Public Class MyButton
Inherits Button
Public Property GroupID As Integer
Public Property AnotherInteger As Integer
End Class
You can access the button by casting the sender
Private Sub PrintMessage(ByVal sender As Object, ByVal e As EventArgs)
Dim btn = DirectCast(sender, MyButton)
MessageBox.Show( _
String.Format("GroupID = {0}, AnotherInteger = {1}", _
btn.GroupID, btn.AnotherInteger))
End Sub
These new properties can even be set in the properties window (under Misc).
The controls defined in the current project automatically appear in the toolbox.
Use the Tag property of the button.
Button1.Tag = someObject
AddressOf gets the address of a method, and thus you cannot pass parameters to it.
You can use delegate which very clear for your code follow as:
Define a delegate
Public Delegate Sub ControlClickDelegate(ByVal sender As Object, ByVal e As EventArgs)
Custom button class
Public Class CustomButton
Inherits System.Windows.Forms.Button
#Region "property delegate"
Private controlClickDelegate As ControlClickDelegate
Public Property ClickHandlerDelegate As ControlClickDelegate
Get
Return controlClickDelegate
End Get
Set(ByVal Value As ControlClickDelegate)
controlClickDelegate = Value
End Set
End Property
#End Region
Public Sub RegisterEventHandler()
AddHandler Me.Click, AddressOf OnClicking
End Sub
Private Sub OnClicking(ByVal sender As Object, e As System.EventArgs)
If (Me.controlClickDelegate IsNot Nothing) Then
Me.controlClickDelegate(sender, e)
End If
End Sub
End Class
MainForm
Public Class MainForm
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.CusButton1.ClickHandlerDelegate = AddressOf Me.btnClick
Me.CusButton1.RegisterEventHandler()
End Sub
Private Sub btnClick(ByVal sender As Object, ByVal e As EventArgs)
Me.TextBox1.Text = "Hello world"
End Sub
End Class
The below worked for me:
Dim bStart = New Button With {.Text = "START"}
AddHandler bStart.Click, Function(sender, e) TriggerProcess(any Long value)
Private Function TriggerProcess(ByVal paramName As Long) As Boolean
' any processing logic
Return True
End Function
My solution:
AddHandler menuItemYear.Items(i).MouseUp, Sub() menu_year(2019)
Private Sub menu_year(ByVal intYear As Integer)
'do something
End Sub
There are few ways to do that depending of the complexity and number of parameters required.
1. Use Tag for adding a complex structure
2. Inherit the the Button class and add the values as class members then populate them before using it. That gives you a lot more flexibility.
If you are using web version
3. You cannot add it to Tag, but for simple values assign it to index use .Attributes.Add("name"). This gets added to the HTML tags and not the Server side. You can then use the index to access a server side structure for complex systems.
4. Use sessions to store values and store the session reference to Name attribute as described above (#3).
No problem ;-)
For example:
Private ComboActionsOnValueChanged As New Dictionary(Of ComboBox, EventHandler)
'somewhere in function
dim del = Sub(theSender, eventArgs)
MsgBox(CType(theSender, ComboBox).Name & " test")
End Sub
ComboActionsOnValueChanged.Add(myCombo, del)
'somewhere else
Dim delTest = ComboActionsOnValueChanged(myCombo)
RemoveHandler myCombo.SelectedValueChanged, delTest
myCombo.DataSource = someDataSource
AddHandler myCombo.SelectedValueChanged, delTest
as we expect, event won't fire after DataSource change in this place

Using private function

Hi
I am using following code to run a private function.
I have two values in my combo box, One and Two and two private functions with the same names, Private Sub One() and Private Sub Two()
I want my application to call the function whatever value user choses in the combo box.
If One is chosen in the combo box, Private function one should be called.
Thanks
Code is below, that does not work
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim vrValue = ComboBox1.Items(1)
Call vrValue()' In this case vrValue is Two, so Two() should be called.
End Sub
Private Sub two()
MsgBox("Function called")
End Sub
Make your subs functions (the only difference is the returning of a value) and put them in their own class:
Public Class RunFunctions
Dim oMessageBox As MessageBox
Public Function One() As String
'oMessageBox = MessageBox
Return "Message One"
End Function
Public Function Two() As String
Return "Message Two"
End Function
End Class
Add Each function from the class as an item in your combo box:
Public Class Combo_Functions
Dim oRunFunction As RunFunctions
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As Object _
, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
MessageBox.Show(ComboBox1.Items(ComboBox1.SelectedIndex()))
End Sub
Private Sub Combo_Functions_Load(ByVal sender As Object _
, ByVal e As System.EventArgs) Handles Me.Load
oRunFunction = New RunFunctions
ComboBox1.Items.Add(oRunFunction.One())
ComboBox1.Items.Add(oRunFunction.Two())
End Sub
End Class
When the combo box is changed (or use the code for the button click) the messagebox for the correct function is executed.
Dim vrValue = ComboBox1.SelectedItem.ToString()
Select vrValue
Case "One"
One()
Else
Two()
End Select
It looks like what you're trying to do is to dynamically call a particular method using a string variable that contains its name. For example, the combo box would contain items "One" and "Two", and you would call the sub named "One" if the first item in the combo box is selected, or the sub named "Two" if the second item is selected. To that end, you may find this article interesting:
http://www.codeproject.com/KB/cs/CallMethodNameInString.aspx
The code in the article is in C#, which shouldn't be too difficult to convert to VB. But here's the translated version of the code for simply invoking a method without passing or returning any parameters (note: I have not tested this code). It simply uses reflection to find the appropriate method:
Public Shared Sub InvokeStringMethod(ByVal typeName As String, ByVal methodName As String)
'Get the type of the class
Dim calledType As Type = Type.[GetType](typeName)
'Invoke the method itself
calledType.InvokeMember(methodName, BindingFlags.InvokeMethod Or BindingFlags.[Public] Or BindingFlags.[Static], Nothing, Nothing, Nothing)
End Sub
You simply pass the name of the class that contains the method(s) you want to call as the typeName and the name of the method itself that you want to call as the methodName:
InvokeStringMethod("MyClass", "Two")