Implementing interface's event in VBA - vba

I have an interface IView:
Option Explicit
Public Event OnClientSelected()
Public Property Get ClientNames() As Variant
End Property
(...)
But I am not able to implement the event in my user form. Properties and subs are allowed to implement, but event not.
Is it possible to make interface implementation with events?

Did you use withevents?
I've done the following, added a test function to your class
Private WithEvents iface As clsIface
Private Sub UserForm_Initialize()
Set iface = New clsIface
End Sub
Private Sub iface_OnClientSelected()
' Event subscription
End Sub
Private Sub UserForm_Click()
iface.test
End Sub
Function added to class
Public Function test()
RaiseEvent OnClientSelected
End Function

Related

Find out from within a class if an event handler exists in another class

A VB.NET 4 question.
Let's assume there exists a class A which contains an event E. In another Class (B), a variable of type A is declared WithEvents. At a certain point withing A's code, there will be a "RaiseEvent E" command. After that, is there a way to know if E was handled within B (just if a handler of event E exists in Class B)?
Obviously E could contain a parameter (i.e. boolean) so that if a handler within B handles it, it could set this parameter to True. This is not what i'm asking though. I would like to know if there is a built-in-to-.NET way to achieve this, without the use of any parameters.
A code example of what i'm trying to avoid (the use of parameter DoSomethingWasHandled):
Public Class A
Public Event DoSomething(ByRef DoSomethingWasHandled As Boolean)
Public Sub RaiseDoSomething()
Dim DoSomethingWasHandled As Boolean = False
RaiseEvent DoSomething(DoSomethingWasHandled)
End Sub
End Class
Public Class B
Public WithEvents SomeA As New A
Private Sub HandleDoSomething(ByRef DoSomethingWasHandled As Boolean) Handles SomeA.DoSomething
DoSomethingWasHandled = True
End Sub
End Class
A code example of what i'm asking if it exists:
Public Class A
Public Event DoSomething()
Public Sub RaiseDoSomething()
RaiseEvent DoSomething()
If DoSomething.WasHandled Then '<-- Does this check exist in any form? ***
DoSomethingElse()
End If
End Sub
End Class
Public Class B
Public WithEvents SomeA As New A
Private Sub HandleDoSomething() Handles SomeA.DoSomething
'DoStuff...
End Sub
End Class
*** This would just check if an event handler of E exists in class B and return True if it does, False if it doesn't.
Like this.
Public Class A
Public Event DoSomething(e As Object)
Public Sub RaiseDoSomething()
' adding 'Event' to the variable name of
' the event allows it to be checked
If DoSomethingEvent IsNot Nothing Then 'does the event have a subscriber(Event Handler)?
'yes
RaiseEvent DoSomething("TEST") 'because there is a handler this will be handled
End If
End Sub
End Class
Public Class B
Public WithEvents SomeA As New A
Private Sub HandleDoSomething(e As Object) Handles SomeA.DoSomething
Debug.WriteLine("Do")
End Sub
End Class
A test
Dim FOOa As New A
Dim fooB As New B
FOOa.RaiseDoSomething()
fooB.SomeA.RaiseDoSomething()

A case for interface?

I have a class that should do different things with a form.
Because these "things" are specific to the form, I store the reference to the form like this:
Friend Class clsEdit
Private m_Form As frmMain
And I pass it to the class like this:
Public Sub New(ByRef uForm As frmMain)
m_Form = uForm
End Sub
Now when my class should do these "things", I do it like this:
MyEditClass.DoThings()
Internally it looks like this:
Public Sub DoThis()
m_Form.SetHookPaused(True)
m_Form.StopCommonTimers()
End Sub
Protected Overrides Sub Finalize()
m_Form.DoSomethingThatOnlyThisFormCanDo()
End Sub
I would now like to be able to use clsEdit on a different form as well.
This other form also has the functions "DoThings" and "DoSomethingThatOnlyThisFormCanDo".
However, when I change the declaration of m_Form to this
Private m_Form As Form
... I can't do this anymore:
m_Form.DoThings()
... because "DoThings" is not a property / function of "Form".
And when I change it to this:
Private m_Form As frmOther
... I can't do that anymore:
Public Sub New(ByRef uForm As frmMain)
m_Form = uForm
End Sub
Can anybody tell me how I could do this?
Create your interface:
Public Interface IFormStuff
Sub SetHookPaused(value As Boolean)
Sub StopCommonTimers()
End Interface
Replace the form variable with the Interface variable in the class:
Public Class clsEdit
Private m_Form As IFormStuff
Public Sub New(f As IFormStuff)
m_Form = f
End Sub
Public Sub DoThis()
m_Form.SetHookPaused(True)
m_Form.StopCommonTimers()
End Sub
End Class
Implement the Interface in each form:
Public Class Form1
Implements IFormStuff
and each form needs to implement those interface stubs:
Public Sub SetHookPaused(value As Boolean) Implements IFormStuff.SetHookPaused
' do something
End Sub
Public Sub StopCommonTimers() Implements IFormStuff.StopCommonTimers
' do something
End Sub
then you need to create the class at the form level:
Private myEdit As clsEdit = Nothing
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
myEdit = New clsEdit(Me)
End Sub
That's the gist of it.

Access variable in Shared Sub

is there a way to access a variable in Form_Load from an event handler?
Please dont mind the code, this is just a representation of my question.
Public Class Form
Public Sub Form_Load()
Dim x as string
x = MyClass.MethodGetValue()
End Sub
Private Shared Sub OnChanged()
MyClass2.MethodGetValue(x)
End Sub
End Class
It's about the scope of the variable. In your situation you need a class variable. This allows it to be used anywhere inside of this class.
Public Class Form1
Private x As Object 'pick the datatype that matches your needs
Public Sub Form_Load()
x = MyClass.MethodGetValue()
End Sub
Private Sub OnChanged()
MyClass2.MethodGetValue(x)
End Sub
End Class

Raise Events Custom Control Class which Inherits Base Class

I'm trying to design a "pass-through" for the axShockwaveFlash control. This control does not have .MouseDown, .MouseUp or .MouseMove events associated with it. Sadly, I need to detect these events on any shockwave controls as they are used in another class (which detects these events on a variety of different controls).
So, I tried designing a custom class, modifying the axShockwaveFlash class to include these events. However, I get the following error:
"Derived classes cannot raise base class events."
on the line:
RaiseEvent MouseDown(Me, EventArgs.Empty)
Full code (minus the up and move functions):
Imports System.Runtime.InteropServices
Imports System.Threading
Public Class MousedFlash
Inherits AxShockwaveFlashObjects.AxShockwaveFlash
'WndProc Inputs:
Private Const WM_RBUTTONDOWN As Integer = &H204
Private Const WM_LBUTTONDOWN As Integer = &H201
Protected Overloads Sub OnMouseDown()
RaiseEvent MouseDown(Me, EventArgs.Empty)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Select Case m.Msg
Case WM_RBUTTONDOWN
Debug.WriteLine("MOUSE FLASH - right down!")
Call OnMouseDown()
Return
Case WM_LBUTTONDOWN
Debug.WriteLine("MOUSE FLASH - left down!")
Call OnMouseDown()
Return
End Select
MyBase.WndProc(m)
End Sub
End Class
I think the Base Class is AxShockwaveFlashObjects - but I can't see the mouse events defined in here. Bit out my depth on this one - any help appreciated.
Having a look at this page it looks like instead of trying to raise the base class event, you should call the Sub which handles that event directly. So try replacing
Protected Overloads Sub OnMouseDown()
RaiseEvent MouseDown(Me, EventArgs.Empty)
End Sub
with
Protected Overloads Sub OnMouseDown()
MyBase.MouseDown(Me, EventArgs.Empty)
End Sub
Thanks. In the end a mixture of carelessness on my part and the wrong type of over-ride. Final working replacement:
Shadows Event MouseDown As System.EventHandler
Protected Overridable Sub OnMouseDownTrigger()
RaiseEvent MouseDown(Me, EventArgs.Empty)
End Sub

referencing form button from another form

I have two forms both with the same buttons on, and I want to have it so that if I click the button both buttons will do the same thing i.e. they are referencing each other on different forms. the way i found was:
Public Class Form2
Dim form1 As New form1
Private Sub Button2_Click
form1.backcolor=black
form2.backcolor=black
end sub
end class
then
Public Class Form1
Dim form2 As New form2
Private Sub Button1_Click
form1.backcolor=black
form2.backcolor=black
end sub
end class
only this doesn't work as there is an error:An unhandled exception of type 'System.StackOverflowException' occurred in System.Windows.Forms.dll as far as i can see there is no infinite loop or stack over flow.
any help would be greatly appreciated.
You have an infinite loop, because each time one of the forms is instantiated, it is instantiating the other. Creating a Form1 will create a Form2, then Form2 immediately creates another Form1 and so on and so on...
Change your code to this:
Public Class Form2
Private Sub Button2_Click
Dim form1 As New Form1
form1.backcolor=black
form2.backcolor=black
End sub
End class
Public Class Form1
Private Sub Button1_Click
form1.backcolor=black
Dim form2 As New Form2
form2.backcolor=black
End sub
End class
Now it will only create the other class instances when you click a button.
Like Karl Anderson said, there is a infinite loop in your code. His solution will create a new form every time you click the button. If you don't want this behavior, I think that the best approach is to use the mediator pattern. And it will be much more easy if you want to add new actions and new forms.
The code will look something like this:
Public Class Mediator
Private forms As New List(Of BaseForm)
Public Sub RegisterForm(form As BaseForm)
forms.Add(form)
End Sub
Public Sub ChangeAllFormsBackColorToBlack()
For Each form In forms
form.ChangeBackColorToBlack()
Next
End Sub
End Class
Public Class BaseForm
Private med As Mediator
Public Sub New(med As Mediator)
Me.med = med
Me.med.RegisterForm(Me)
End Sub
Public Sub ChangeBackColorToBlack()
backcolor = black
End Sub
Public Sub OnButtonClick()
Me.med.ChangeAllFormsBackColorToBlack()
End Sub
End Class
Public Class Form2
Inherits BaseForm
Public Sub New(med As Mediator)
MyBase.New(med)
End Sub
Private Sub Button2_Click()
Me.OnButtonClick()
End Sub
End Class
Public Class Form1
Inherits BaseForm
Public Sub New(med As Mediator)
MyBase.New(med)
End Sub
Private Sub Button1_Click()
Me.OnButtonClick()
End Sub
End Class
Module MediatorDemo
Sub Main()
Dim med As New Mediator
Dim f1 As New Form1(med)
Dim f2 As New Form2(med)
f1.OnButtonClick()
End Sub
End Module