I'm trying to understand how I can expose an event in this situation:
Class C has an event E
Class B instance an object of class C
Class A instance an object of class B
When the event is raised from class C, is possible to manage it directly from class A?
Public Class C
Public Event E()
Public Sub Function_of_C()
RaiseEvent E()
End Sub
End Class
Public Class B
Public WithEvents m_C as new C
End Class
Public Class A
Public WithEvents m_B as new B
Private Sub Function_of_A() Handles m_B.m_C.E '<-- Doesn't work
'Do something
End Sub
End Class
As explained in the comment to your question. You need to bubble up the event in class B when it receives from C.
Sub Main
Dim test = new A()
End Sub
Public Class C
Public Event E()
Public Sub Function_of_C()
RaiseEvent E()
End Sub
End Class
Public Class B
Public WithEvents m_C as new C
Public Event E()
Public Sub FnB() Handles m_C.E
Console.WriteLine("In B received Event from C")
RaiseEvent E()
End Sub
Public Sub TriggerC()
Console.WriteLine("In B TriggerC, call C.Function_Of_C")
m_C.Function_Of_C()
End Sub
End Class
Public Class A
Public WithEvents m_B as new B
Private Sub Function_of_A() Handles m_B.E
Console.WriteLine("In A received Event from B")
End Sub
public Sub New()
Console.WriteLine("In A constructor, call B.TriggerC")
m_b.TriggerC()
End Sub
End Class
Just as a supplement to Steve's answer, here's an example of the common design pattern to forward events:
Public Class Doorbell
Public Event Ding As EventHandler
Protected Overridable Sub OnDing(e As EventArgs)
RaiseEvent Ding(Me, e)
End Sub
Friend Sub RaiseDing()
Me.OnDing(EventArgs.Empty)
End Sub
End Class
Public Class House
Implements IDisposable
Public Event DoorbellDing As EventHandler
Public Property Doorbell() As Doorbell
Get
Return Me.m_doorbell
End Get
Set(value As Doorbell)
If (Not value Is Me.m_doorbell) Then
Me.UnookDoorbell()
Me.m_doorbell = value
Me.HookDoorbell()
End If
End Set
End Property
Public Sub Dispose() Implements IDisposable.Dispose
Me.UnookDoorbell()
End Sub
Private Sub HandleDoorbellDing(sender As Object, e As EventArgs)
Me.OnDoorbellDing(e)
End Sub
Private Sub OnDoorbellDing(e As EventArgs)
RaiseEvent DoorbellDing(Me, e)
End Sub
Private Sub HookDoorbell()
If (Not Me.m_doorbell Is Nothing) Then
AddHandler Me.m_doorbell.Ding, AddressOf Me.HandleDoorbellDing
End If
End Sub
Private Sub UnookDoorbell()
If (Not Me.m_doorbell Is Nothing) Then
RemoveHandler Me.m_doorbell.Ding, AddressOf Me.HandleDoorbellDing
End If
End Sub
Private m_doorbell As Doorbell
End Class
Related
I have created a custom class
Public Class MyFSW
Inherits FileSystemWatcher
Public Property ParentForm As Form
Public Property TabPage As TabPage
End Class
Now I want to add a custom event to the this class, that fires when the property "EnableRaisingEvents" of the FileSystemWatcher changes?
Is there any chance to do this?
The EnableRaisingEvents property is not declared Overridable so you can't override it. You can shadow it though:
Public Class FileSystemWatcherEx
Inherits FileSystemWatcher
Public Property ParentForm As Form
Public Property TabPage As TabPage
Public Shadows Property EnableRaisingEvents As Boolean
Get
Return MyBase.EnableRaisingEvents
End Get
Set(value As Boolean)
If MyBase.EnableRaisingEvents <> value Then
MyBase.EnableRaisingEvents = value
OnEnableRaisingEventsChanged(EventArgs.Empty)
End If
End Set
End Property
Public Event EnableRaisingEventsChanged As EventHandler
Protected Overridable Sub OnEnableRaisingEventsChanged(e As EventArgs)
RaiseEvent EnableRaisingEventsChanged(Me, e)
End Sub
End Class
That will work as long as you set the property through a reference of type FileSystemWatcherEx. Because the property is shadowed rather than overridden, setting it through a reference of type FileSystemWatcher will bypass the derived property implementation and the event will not be raised. You really can't do anything about that.
Thank you so far!
This is what I got now (in my class-file):
Public Class MyFSW
Inherits FileSystemWatcher
Public Property ParentForm As Form
Public Property TabPage As TabPage
Public Shadows Property EnableRaisingEvents As Boolean
Get
Return MyBase.EnableRaisingEvents
End Get
Set(value As Boolean)
If MyBase.EnableRaisingEvents <> value Then
MyBase.EnableRaisingEvents = value
OnEnableRaisingEventsChanged(EventArgs.Empty)
End If
End Set
End Property
Public Event EnableRaisingEventsChanged As EventHandler
Protected Overridable Sub OnEnableRaisingEventsChanged(e As EventArgs)
RaiseEvent EnableRaisingEventsChanged(Me, e)
End Sub
End Class
In my Form-Class is got this:
Sub CreateFSW()
w.Watcher = New MyFSW With {
.ParentForm = f,
.TabPage = tp,
.Path = w.Path,
.Filter = w.Filter,
.IncludeSubdirectories = w.IncludeSubdirs,
.NotifyFilter = DirectCast(w.NotifyFilter, NotifyFilters)
}
AddHandler w.Watcher.Created, AddressOf Fsw_EventRaise
AddHandler w.Watcher.Changed, AddressOf Fsw_EventRaise
AddHandler w.Watcher.Renamed, AddressOf Fsw_EventRaise
AddHandler w.Watcher.Deleted, AddressOf Fsw_EventRaise
AddHandler w.Watcher.EnableRaisingEventsChanged, AddressOf Fsw_Event
End Sub
Private Sub Fsw_Event(sender As Object, e As FileSystemEventArgs)
MessageBox.Show("Works")
End Sub
The compiler says:
Option Strict On does not allow narrowing in implicit type conversions between method Fsw_Event(sender As Object, e As FileSystemEventArgs) and delegate Delegate Sub EventHandler(sender As Object, e As EventArgs)
Seems that some types does not match. I tried to change FileSystemEventArgs to EventArgs and stuff like this, but without luck.
As a continuation of a “previous example” you can achieve that with some small changes like the example below shows:
In this example the property is changed by clicking a button, but you can implement handlers on your own needs.
Option Strict On
Imports System.IO
Public Class Form1
Private Fsw As CustomFSW
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CreateFSW()
End Sub
Sub CreateFSW()
Fsw = New CustomFSW With {
.Name = "Tab1", 'Adding this you can specify the object is sending the event
.Path = "C:\Users\UserName\Desktop\Test\",
.Filter = "*.*",
.IncludeSubdirectories = True,
.EnableRaisingEvents = True
}
AddHandler Fsw.Created, AddressOf Fsw_Event
AddHandler Fsw.Changed, AddressOf Fsw_Event
AddHandler Fsw.Renamed, AddressOf Fsw_Event
AddHandler Fsw.Deleted, AddressOf Fsw_Event
'Here the handler of your custom event
AddHandler Fsw.MyCutomEvent, AddressOf Fsw_CutomEvent
End Sub
Private Class CustomFSW
Inherits FileSystemWatcher
Private counter As Integer = 0
Public Property Name As String
'You can use the base property instead of this for specific needs
Private _EnableRaisingEvents As Boolean
Public Overloads Property EnableRaisingEvents As Boolean
Get
Return _EnableRaisingEvents
End Get
Set(value As Boolean)
If Not value = _EnableRaisingEvents Then
counter += 1
RaiseEvent MyCutomEvent(Me, "Ciaooo, EnableRaisingEvents is changed " & counter.ToString & " times")
End If
_EnableRaisingEvents = value
End Set
End Property
'Rename this on your needs
Public Event MyCustomEvent(sender As Object, e As String)
End Class
Private Sub Fsw_CustomEvent(sender As Object, e As String)
' Do your stuff here
MsgBox(e)
End Sub
Private Sub Fsw_Event(sender As Object, e As FileSystemEventArgs)
Dim FSW As CustomFSW = CType(sender, CustomFSW)
If Not String.IsNullOrEmpty(FSW.Name) Then
Select Case FSW.Name
Case "Tab1"
'Do something
Debug.WriteLine("Event generated from: " & FSW.Name)
Case "Tab2"
'Do something else
Debug.WriteLine("Event generated from: " & FSW.Name)
End Select
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If Fsw IsNot Nothing Then
Fsw.EnableRaisingEvents = Not Fsw.EnableRaisingEvents
End If
End Sub
End Class
I'm builing an app for windows iot core on a raspberry pi 3.
It is a scoreboard fot playing billiard.
The app has to work with a numpad only.
The problem is, I want to navigate between pages when the user presses the enter key, but after a couple of times de enter key doesn't work anymore.
I have made a simple code to let you see what i mean.
mainpage and onother two pages. This is the testcode.
The mainpage
Imports Windows.UI.Core
Public NotInheritable Class MainPage
Inherits Page
Public Sub New()
Me.InitializeComponent()
AddHandler Window.Current.CoreWindow.KeyUp, AddressOf CoreWindow_KeyUp
End Sub
Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
End Sub
Private Sub CoreWindow_KeyUp(sender As CoreWindow, e As KeyEventArgs)
Dim Value As String = e.VirtualKey
'Enter
If Value = "13" Then
GotoNext()
End If
End Sub
Private Sub GotoNext()
Frame.Navigate(GetType(BlankPage1))
End Sub
End Class
Page 1
Imports Windows.UI.Core
Public NotInheritable Class BlankPage1
Inherits Page
Public Sub New()
Me.InitializeComponent()
AddHandler Window.Current.CoreWindow.KeyUp, AddressOf CoreWindow_KeyUp
End Sub
Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
End Sub
Private Sub CoreWindow_KeyUp(sender As CoreWindow, e As KeyEventArgs)
Dim Value As String = e.VirtualKey
'Enter button
If Value = "13" Then
GotoNext()
End If
End Sub
Private Sub GotoNext()
Frame.Navigate(GetType(Blankpage2))
End Sub
End Class
Page 2
Imports Windows.UI.Core
Public NotInheritable Class BlankPage2
Inherits Page
Public Sub New()
Me.InitializeComponent()
AddHandler Window.Current.CoreWindow.KeyUp, AddressOf CoreWindow_KeyUp
End Sub
Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
End Sub
Private Sub CoreWindow_KeyUp(sender As CoreWindow, e As KeyEventArgs)
'we halen de virtuele waarde van de ingedrukte knop op
Dim Value As String = e.VirtualKey
'Enter knop
If Value = "13" Then
GotoNext()
End If
End Sub
Private Sub GotoNext()
Frame.Navigate(GetType(MainPage))
End Sub
End Class
Strangely when you hit enter 9 times it stops and I don't know why.
I am in a situation where i have a single helper class that i re-use on most of my forms. and it happens that my helper class needs to call a function from that form as well
Public Class Form1
Dim hc As HelperClass
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
hc = New HelperClass
End Sub
Private Sub someForm1Sub()
'do something
End Sub
End Class
Public Class Form2
Dim hc As HelperClass
Private Sub Form2_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
hc = New HelperClass
End Sub
Private Sub someForm2Sub()
'do something
End Sub
End Class
Public Class Form3
Dim hc As HelperClass
Private Sub Form3_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
hc = New HelperClass
End Sub
Private Sub someForm3Sub()
'do something
End Sub
End Class
Public Class HelperClass
'i need to call here someForm1Sub(), someForm2Sub(), someForm3Sub()
'but it bases on which form uses this class
End Class
i think that there are many ways to do this. I have read some about delegate function, but i do not know how to pass a delegate to other class. I am using vb.net 2010. Please provide the best way to do this
please reply thanks.
You can pass a delegate to a method using the AddressOf keyword. For example,
Public Sub Test()
' Make Foo() call the Bar() method.
Foo(AddressOf Bar)
End Sub
Public Sub Foo(d As Action)
' Call the delegate.
d()
End Sub
Public Sub Bar()
Console.WriteLine("Bar was called.")
End Sub
But, as you say, there are many ways you could do this. One possible solution which may be a bit nicer than passing delegates (especially if there are a few methods in the form that could be called by the helper class) would be to have Form1, Form2 and Form3 all implement an interface, and have the HelperClass call a method on the interface. An instance of the interface could then be given to HelperClass in its constructor.
For example,
Public Interface IForm
Sub DoStuff()
End Interface
Public Class Form2
Implements IForm
Dim hc As HelperClass
Private Sub Form2_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
hc = New HelperClass(Me)
End Sub
Public Sub DoStuff() Implements IForm.DoStuff
' Do stuff here.
End Sub
End Class
Public Class HelperClass
Private _form As IForm
Public Sub New(form as IForm)
_form = form
End Sub
Public Sub MakeTheFormDoStuff()
_form.DoStuff()
End Sub
End Class
I have created an application.
The main form is "Form1".
I have declared a class in Form1 like this:
Public Class Form1
Private _MyClass As Class1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
_MyClass = New Class1
End Sub
End Class
Class1 is declared like this:
Public Class Class1
Private f As Form2
Public Sub New()
f = New Form2
f.Show()
End Sub
End Class
When I click Button1 on the main form, _MyClass1 is created and Form2 is shown.
Now when I click Button1 for the second time, I expect _MyClass1 to destroyed and a new _MyClass1 to be created.
I expect the first Form2 to disappear because _MyClass1 is destroyed.
I think it only exists in _MyClass1, and since _MyClass1 is destroyed, Form2 should also be unloaded.
Instead, I suddenly have two Form2 windows open.
Where did I go wrong in my thinking?
Coming from VB6, I expect a form to be automatically unloaded if its hosting class is terminated. Isn't this so in VB.NET as well?
You Can use :
Public Class Form1
Private _MyClass As Class1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If Not _MyClass Is Nothing Then ' To check if Class is initialized, If so then Close the Class or form
_MyClass.close()
End If
_MyClass = New Class1
End Sub
End Class
Public Class Class1
Private f As Form2
Public Sub New()
f = New Form2
f.Text = "form2"
f.Show()
End Sub
Public Sub close()
f.Close()
Me.Finalize() ' Call Destructor
End Sub
End Class
You have a private form inside a private class inside a form. IDisposable is precisely for class (forms are classes) which create other disposable objects (CA will tell you when you have code that creates stuff that is not disposed of properly as with 2 out 3 of your matryoshka dolls):
Public Class Class1
Implements IDisposable
Private f As Form2
Public Sub New()
f = New Form2
f.Text = "form2"
f.Show()
End Sub
Private disposedValue As Boolean ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
If f IsNot Nothing Then
f.Close() ' or f.Dispose
End If
End If
End If
Me.disposedValue = True
End Sub
' VS generated code
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
End Class
one tweak to Form1.Designer.vb (CA will tell you about it):
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
_MyClass.Dispose() ' dispose of your toys
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
The button click:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' depending on what the point is, this will work:
If _MyClass Is Nothing Then
_MyClass = New Class1
End If
' if you really need it start anew:
' If _MyClass IsNot Nothing Then
' _MyClass.Dispose
' End If
' _MyClass = New Class1
End Sub
When you again click on button. It will not Destroy Previous object of class.
Every time when you click Button A new Instance or Object is created for class1.
I'm working on developing an application that talks to a family of USB sensors. I've created a basic implementation that utilizes a class called Sensor. The class contains events and methods that allow for interaction with the sensor (there is also a threaded task processor involved but I'll go with a simple example).
My issue is that this simple proof of concept example works fine but now I need to expand the application to support the whole family of sensors. To do this I've created a BaseSensor class with all the appropriate methods and events and then I've created multiple subclasses such as SensorA, SensorB, and SensorC that all inherent BaseSensor.
This seemed like a good application of polymorphism so I've created a Shared function on BaseSensor called Initialize that does an initial USB communication and returns the correct object depending on the sensor type (SensorA, SensorB, SensorC). This works fine however it seems I can not find a way to correctly declare the object With Events. See the sample code for my deliema.
Attempt 1:
Public Class Form1
Dim WithEvents oBaseClass As BaseClass
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
oBaseClass = New ExtendedClass
oBaseClass.Test() 'This doesn't work because the object was type casted.
End Sub
Private Sub TestEventHdlr() Handles oBaseClass.TestEvent
MsgBox("Event Fired")
End Sub
End Class
Public Class BaseClass
Public Event TestEvent()
End Class
Public Class ExtendedClass
Inherits BaseClass
Public Sub Test()
MsgBox("Test")
End Sub
End Class
Attempt 2:
Public Class Form1
Dim WithEvents oBaseClass 'This doesn't work.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
oBaseClass = New ExtendedClass
oBaseClass.Test()
End Sub
Private Sub TestEventHdlr() Handles oBaseClass.TestEvent
MsgBox("Event Fired")
End Sub
End Class
Public Class BaseClass
Public Event TestEvent()
End Class
Public Class ExtendedClass
Inherits BaseClass
Public Sub Test()
MsgBox("Test")
End Sub
End Class
I'm missing something here. How should I proceed?
WithEvents can not be late bound. You need to declare your field with a type. If all objects used in this scenario derive from a common base, you will be doing yourself a huge favor in ditching late binding. Cast when necessary, and declare virtual (overridable) methods to implement your polymorphism.
Public Class Form1
Dim WithEvents oBaseClass As BaseClass 'Early bound'
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
oBaseClass = New ExtendedClass
DirectCast(oBaseClass, ExtendedClass).Test() 'Casting to call a method'
End Sub
Private Sub TestEventHdlr() Handles oBaseClass.TestEvent
MsgBox("Event Fired")
End Sub
End Class
Public Class BaseClass
Public Event TestEvent()
End Class
Public Class ExtendedClass
Inherits BaseClass
Public Sub Test()
MsgBox("Test")
End Sub
End Class
is this what your looking for?
Public Class Form1
Private WithEvents oBaseClass As ExtendedClass
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
oBaseClass = New ExtendedClass
oBaseClass.Test()
End Sub
Private Sub TestEventHdlr() Handles oBaseClass.TestEvent
MsgBox("Event Fired")
End Sub
End Class
Public Class BaseClass
Public Event TestEvent()
Friend Sub raiseTestEvent()
RaiseEvent TestEvent()
End Sub
End Class
Public Class ExtendedClass
Inherits BaseClass
Public Sub Test()
MsgBox("Test")
raiseTestEvent()
End Sub
End Class
if not, you need to create an interface and declare it in your form and setting the corresponding class to it in the form_load
Adjusted slightly to raise the event in case you wanted an example of that, altered the event a bit as well to provide a bit different approach.
Public Class Form1
Dim oBaseClass As BaseClass 'Early bound'
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
oBaseClass = New ExtendedClass
If TypeOf oBaseClass Is BaseClass Then
AddHandler DirectCast(oBaseClass, BaseClass).TestEvent, AddressOf TestEventHdlr
End If
oBaseClass.Test()
End Sub
Private Sub TestEventHdlr()
MsgBox("Event Fired")
End Sub
End Class
Public Class BaseClass
Public Event TestEvent()
Public Overridable Sub Test()
RaiseEvent TestEvent()
End Sub
End Class
Public Class ExtendedClass
Inherits BaseClass
Public Overrides Sub Test()
MyBase.Test()
MsgBox("Test")
End Sub
End Class
Depending on the types of behaviour you're looking to model, you might want to consider using Interfaces instead of Inheritence or a mixture of both. Rather than having a base object that defines the event, define behaviours or functions based around interfaces and implement those in the equivilent of your ExtendedClass
This annoyed me a lot too but it kind of forced me to learn about them and as you can implement multiple interface types per object it's ultimately very flexible.
One tip though: think about interface content first. Although VS auto inserts method/property stubs for you, if you later change the definition of the interface it's a manual effort to update the implementations.
Simon