Outlook VSTO App - VB - BeforeReminderShow event not working - vb.net

I am performing some actions on Outlook's Application_Reminder event. After actions are done, I want to dismiss/remove the reminder (as not to run actions later unintentionally due to second reminder of appointment) with the codes below but breakpoints not hit in _BeforeReminderShow event, not fired. Any idea on what I am missing ?
Imports System.Windows.Forms
Imports System.Windows.Interop
Imports Microsoft.Office.Interop.Outlook
Imports Microsoft.Office.Tools
Imports System.IO
Imports System.Text
Public Class ThisAddIn
Private WithEvents ObjReminders As Reminders
Private Sub ObjReminders_BeforeReminderShow(Cancel As Boolean)
For Each objRem In ObjReminders
If objRem.Caption = "testing" Then
If objRem.IsVisible Then
objRem.Dismiss
Cancel = True
End If
Exit For
End If
Next objRem
End Sub
I also tried the version below after eugene's reply but it also does not reach to BeforeReminderShow event.
Public Class ThisAddIn
Private WithEvents OlRemind As Microsoft.Office.Interop.Outlook.Reminders
Private Sub OlRemind_BeforeReminderShow(Cancel As Boolean)
OlRemind = Application.Reminders
For Each objRem In OlRemind
If objRem.Caption = "testing" Then
If objRem.IsVisible Then
objRem.Dismiss
Cancel = True
End If
Exit For
End If
Next objRem
End Sub

You need to initialize the source object, declaring the reminder object is not enough. So, anywhere in the code you could run the following command:
Set ObjReminders = Application.Reminders
Your code could look in the following way:
' declare this object withEvents throwing all the events
Private WithEvents olRemind As Outlook.Reminders
' run somewhere to initialize the source object
Set olRemind = Application.Reminders
Private Sub olRemind_BeforeReminderShow(Cancel As Boolean)
For Each objRem In olRemind
If objRem.Caption = "TESTING" Then
If objRem.IsVisible Then
objRem.Dismiss
Cancel = True
End If
Exit For
End If
Next objRem
End Sub

You still need to initialize the olRemind object when your addin starts up and you need to either add Handles olRemind.BeforeReminderShow or use AddHandler.
See https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/how-to-call-an-event-handler

Related

Outlook VBA event handler not called

I have the following ThisOutlookSession in Outlook:
Public Sub Application_Startup()
Call GetItemsFolderPath.Initialize
End Sub
And the following GetItemsFolderPath class module:
Public WithEvents myOlExp As Outlook.Explorer
Public Sub Initialize()
Set myOlExp = Application.ActiveExplorer
End Sub
Private Sub myOlExp_SelectionChange()
MsgBox "Hello, world"
End Sub
I'm basically following the docs from https://learn.microsoft.com/en-ca/office/vba/api/Outlook.Explorer.SelectionChange
The code compiles BUT it never shows the MsgBox
Restarting Outlook so Application_Startup is called didn't work
Manually executing the Application_Startup macro didn't help either
Any ideas - what am I doing wrong?
When adding Dim GetItemsFolderPath As New GetItemsFolderPath in global space, the code work as it should, displaying the messagebox when you switch folder in Outlook.
ThisOutlookSession:
Option Explicit
Dim GetItemsFolderPath As New GetItemsFolderPath 'Instantiate the class
'***************************************************
'* Outlook start
'*
Public Sub Application_Startup()
Call GetItemsFolderPath.Initialize
End Sub
Class module GetItemsFolderPath:
Option Explicit
Public WithEvents myOlExp As Outlook.Explorer
Public Sub Initialize()
Set myOlExp = Application.ActiveExplorer
End Sub
Private Sub myOlExp_SelectionChange()
MsgBox "Hello, world"
End Sub
I ran into the following problem:
https://learn.microsoft.com/en-us/outlook/troubleshoot/deployment/macros-in-this-project-disabled-outlook

VBA CommandBarButton does not run code OnAction

Once the button is pressed it does not perform the subroutine defined OnAction method.
I have checked all the Security options in Access are enabled and have written the same code in different ways.
I have tried to run a function with the OnAction method instead.
Private Sub Check_Status_Click()
Dim cmdBAR As CommandBar
Dim cmdButton1 As CommandBarButton
Set cmdBAR = CommandBars.Add(, msoBarPopup, False, True)
Set cmdButton1 = cmdBAR.Controls.Add(msoControlButton)
cmdButton1.Caption = "Dale"
cmdButton1.OnAction = "Dale"
cmdBAR.ShowPopup
'Clean
Set cmdBAR = Nothing
Set cmdButton1 = Nothing
End Sub
Public Sub Dale()
MsgBox "hola"
End Sub
I dont get any error, just it is not doing anything even the menu shows up.
Actually OnAction subroutine needs to be
public sub
in public module
So you should change your code to something like this:
...
cmdButton1.Caption = "Dale"
cmdButton1.OnAction = "Dale"
cmdBAR.ShowPopup
...
And place your sub into some public module:
Public Sub Dale()
MsgBox "hola"
End Sub

Handling custom events using modeless form & user defined classes

I'm trying to display the progress of various routines on a modeless form, by having those routines raise custom events detailing their progress. The form should handle those events to display appropriate information.
The problem is that although RaiseEvent is called, the event handlers don't then do anything.
The intended result of the following code is the two debug.prints would be called whenever an event is raised by triggerTest.
The only success I've had is with raising the error within the userform, by CommandButton1_Click in the following code. The form's event handler then kicks in (rather redundantly, but perhaps that means I'm on the right path).
Thanks
Event class clsChangeProgressTrigger
Option Explicit
Public Enum geProgressStatus
geProgressStatusComplete = -1
geProgressStatusRestart = -2
End Enum
Public Event ChangeProgress(dProgress As Double, sProcedure As String)
'
Public Sub Update(dProgress As Double, sProcedure As String)
RaiseEvent ChangeProgress(dProgress, sProcedure)
End Sub
Public Sub Complete(sProcedure As String)
RaiseEvent ChangeProgress(geProgressStatusComplete, sProcedure)
End Sub
Public Sub Restart(sProcedure As String)
RaiseEvent ChangeProgress(geProgressStatusRestart, sProcedure)
End Sub
User form frmOutput
Option Explicit
Private WithEvents mProgressTrigger As clsChangeProgressTrigger
'
Private Sub CommandButton1_Click()
Call mProgressTrigger.Update(12.34, "SomeValue")
End Sub
Private Sub CommandButton2_Click()
Call modZTest.triggerTest
End Sub
Private Sub UserForm_Initialize()
Set mProgressTrigger = New clsChangeProgressTrigger
End Sub
Private Sub mProgressTrigger_ChangeProgress(dProgress As Double, sProcedure As String)
Debug.Print "Form Event Handled"
End Sub
Event test class clsEventTest
Option Explicit
Private WithEvents mProgressTrigger As clsChangeProgressTrigger
'
Private Sub mProgressTrigger_ChangeProgress(dProgress As Double, sProcedure As String)
Debug.Print "Class Event Handled"
End Sub
Private Sub Class_Initialize()
Set mProgressTrigger = New clsChangeProgressTrigger
End Sub
Test wrapper in public module modZTest
Public Sub triggerTest()
Application.EnableEvents = True
' Instantiate Trigger class for this routine
' Dim cChangeProgressTrigger As clsChangeProgressTrigger
Set gChangeProgressTrigger = New clsChangeProgressTrigger
' Instantiate Event Test class, which should handle raised event
Dim cEventTest As clsEventTest
Set cEventTest = New clsEventTest
' Instantiate user form, which should handle raised event
Set gfrmOutput = New frmOutput ' Modeless form, gfrmOutput has global scope
gfrmOutput.Show
Stop
' Raise an event
Call gChangeProgressTrigger.Complete("SomeValue")
' Tidy Up
Set gfrmOutput = Nothing
Set gChangeProgressTrigger = Nothing
Set cEventTest = Nothing
End Sub
Thanks Dee, that helped me along to the solution.
With this declared as global scope:
Public gChangeProgressTrigger As clsChangeProgressTrigger
I had to change the class / form level initialisations as follows:
Private Sub UserForm_Initialize()
' Set mProgressTrigger = New clsChangeProgressTrigger ' Old
Set mProgressTrigger = gChangeProgressTrigger ' New
End Sub
and
Private Sub Class_Initialize()
' Set mProgressTrigger = New clsChangeProgressTrigger ' Old
Set mProgressTrigger = gChangeProgressTrigger ' New
End Sub
Then the event handlers fired as desired.

Cannot update UI from other task in win forms?

I have four complex tasks running parallel, I want to update a rich textbox with the log file.
The approximate program structure is as follows:
Sub buttonClick ()
complextask1 'code goes here
complextask2 'code goes here
complextask3 'code goes here
complextask4 'code goes here
end sub
The above four tasks updates a log file, which I have to display in a RichTextbox control.
I tried with an infinite while loop, and updating the textbox, but my UI is getting hanged.
You must run heavy task in separate thread or background worker
First read and study about threading here is a sample coding for you task
Import these to your form class
Imports System.Threading
Imports System.ComponentModel
Create a local variable in your form
Private syncContext As SynchronizationContext
Create method for your task
Private sub DoTask()
complextask1 'code goes here
complextask2 'code goes here
complextask3 'code goes here
complextask4 'code goes here
End Sub
On button click create new thread and execute heavy task
Sub buttonClick ()
syncContext = AsyncOperationManager.SynchronizationContext()
Dim newThread As Thread
newThread = New Thread(AddressOf DoTask)
newThread.Start()
End Sub
To update your UI status create one method for it
Private sub UpdateStatus(byval State As Object)
Dim myText As String = CType(State, String)
End Sub
Now to call UI method use following statement in your DoTask Method
Dim NewStatus As String = “This Is New Status”
syncContext.Post(New SendOrPostCallback(AddressOf UpdateStatus), NewStatus)
complete code will look like this
Imports System.Threading
Imports System.ComponentModel
Public Class Form1
Private syncContext As SynchronizationContext
Private Sub buttonClick ()
syncContext = AsyncOperationManager.SynchronizationContext()
Dim newThread As Thread
newThread = New Thread(AddressOf DoTask)
newThread.Start()
End Sub
Private sub DoTask()
Dim NewStatus As String
complextask1 'code goes here
NewStatus=”New Task Done”
syncContext.Post(New SendOrPostCallback(AddressOf UpdateStatus), NewStatus)
complextask2 'code goes here
NewStatus=”New Task Done”
syncContext.Post(New SendOrPostCallback(AddressOf UpdateStatus), NewStatus)
complextask3 'code goes here
NewStatus=”New Task Done”
syncContext.Post(New SendOrPostCallback(AddressOf UpdateStatus), NewStatus)
complextask4 'code goes here
NewStatus=”New Task Done”
syncContext.Post(New SendOrPostCallback(AddressOf UpdateStatus), NewStatus)
End Sub
Private sub UpdateStatus(byval State As Object)
Dim myText As String = CType(State, String)
End Sub
End Class

Programmatically adding a commandbutton to a userform

In excel vba I have added a commandbutton to userform... like below
Set ctrl = Me.Controls.Add( _
bstrProgID:="Forms.CommandButton.1", _
Name:="CommandButton1", Visible:=True)
Now I wanted to know how would I tell it what to do when it is clicked?
This is one of those techniques that vba will let you do, but you probably shouldn't. For all the same reasons you shouldn't use code that alters your code.
That said, here is how to do what you want. First insert a class module and name it DynBtn, then paste this code into it:
Private WithEvents mobjBtn As MSForms.CommandButton
Private msOnAction As String
''// This has to be generic or call by name won't be able to find the methods
''// in your form.
Private mobjParent As Object
Public Property Get Object() As MSForms.CommandButton
Set Object = mobjBtn
End Property
Public Function Load(ByVal parentFormName As Object, ByVal btn As MSForms.CommandButton, ByVal procedure As String) As DynBtn
Set mobjParent = parentFormName
Set mobjBtn = btn
msOnAction = procedure
Set Load = Me
End Function
Private Sub Class_Terminate()
Set mobjParent = Nothing
Set mobjBtn = Nothing
End Sub
Private Sub mobjBtn_Click()
CallByName mobjParent, msOnAction, VbMethod
End Sub
Now to use this in your form, create a blank user form and paste this code into it:
Private Const mcsCmdBtn As String = "Forms.CommandButton.1"
Private mBtn() As DynBtn
Private Sub UserForm_Initialize()
Dim i As Long
ReDim mBtn(1) As DynBtn
For i = 0 To UBound(mBtn)
Set mBtn(i) = New DynBtn
Next
''// One Liner
mBtn(0).Load(Me, Me.Controls.Add(mcsCmdBtn, "Btn1", True), "DoSomething").Object.Caption = "Test 1"
''// Or using with block.
With mBtn(1).Load(Me, Me.Controls.Add(mcsCmdBtn, "Btn2", True), "DoSomethingElse").Object
.Caption = "Test 2"
.Top = .Height + 10
End With
End Sub
Public Sub DoSomething()
MsgBox "It Worked!"
End Sub
Public Sub DoSomethingElse()
MsgBox "Yay!"
End Sub
Private Sub UserForm_Terminate()
Erase mBtn
End Sub