SelectionChane is called but ActiveExplorer().Selection.Count = 0 in Outlook VSTO AddIn: - vsto

I try to get the currently selected AppointmentItem. For this, I handle the SelectionChange Event of the ActiveExplorer.
SelectionChange is called often but when I try to get the Selection the count = 0. Is this a known bug of Outlook? You can check this for yourself with:
[...]
currentExplorer.SelectionChange += new Outlook.ExplorerEvents_10_SelectionChangeEventHandler(Selection_Change);
[...]
then handle the events here:
private void Selection_Change()
{
log.Info("currently selected: "+this.Application.ActiveExplorer.Selection.Count);
}
Run your addon open the calendar or the inbox. I/you will get a lot of "currently selected: 0"
But in the documentation, it says apart from FileFolders Outlook automatically selects the first item in the current view: https://learn.microsoft.com/en-us/previous-versions/office/developer/office-2010/bb645132(v%3Doffice.14) Therefore Selection.Count shouldn't be 0???
Any advice on this

The Selection.Count property returns an integer that indicates the number of items or conversation headers in the selection. It works like a charm on my machine. Most probably something is wrong with your code - you have got multiple explorer windows opened and get the selection object from non-active one and etc.

There is absolutely nothing wrong with Selection.Count == 0. Switch to the Calendar folder in the Calendar view and click a time slot with no appointment - Selection.Count will be 0.

Related

Outlook Instant Search - hit and miss results

I have the below code to run an instant search from a tool I've developed that iterates through all Outlook folders and then uses the restrict method to get two counts, first the total and the second, a count of those items that are two years or older.
Once done, this is displayed to the user in a listview and the code below is supposed to do an instant search query on the selected result using the 'received' date to limit the results.
What I've found is that sometimes the instant result filters the results and in other cases it purely displays all items from within the selected folder. For example, a folder has 90 items but 5 are over 2 years old, sometimes it will show 5 (generally after the selection has been made from the listview twice) and the rest of the time the full 90 are shown.
Has anyone else come across this is and managed to resolve it?
Private Sub OpenOlFolder(sender As Object, e As EventArgs) Handles lvwProgress.DoubleClick
With olApp.ActiveExplorer
'// CLEAR SEARCH
.ClearSearch()
'// SWITCH TO SELECTED FOLDER
.CurrentFolder = GetOlFolderFromPath(Me.lvwProgress.Items(Me.lvwProgress.FocusedItem.Index).SubItems(0).Text)
'// DO SEARCH
.Search(String.Concat("received:<", RetentionDate.ToString("MM/dd/yyyy")), Outlook.OlSearchScope.olSearchScopeCurrentFolder)
End With
End Sub
In your code I have noticed multiple dots in the single line of code. It is hard to understand where your code fails if something unexpected happens. So, breaking the chain of property and method calls is essential in troubleshooting such cases.
In the code you change the current folder by setting the CurrentFolder property of the Explorer class. It is a time-consuming operation, so it make sense to wait until it is done. For example, you may try to run the Search method in the Explorer.FolderSwitch event which is fired when when the explorer goes to a new folder, either as a result of user action or through program code.
Also it make sense to do the same operation manually to make sure the filter is correct.

In a VBA Userform, which event is triggered when exiting a filed

I'm using Microsoft Office Professional Plus (64 bit) on a Windows 10 (64 bit) platform. I have a subroutine that is processed when I make a change to a Userform field called MyDate. It's called Private Sub MyDate_AfterUpdate(). It's the second field on a form. It works fine as long as the contents of the MyDate field are edited. However, if the user doesn't need to update the contents of the MyDate field because they accept the default of the field and just presses the tab key past that second field, I'd still like the subroutine to be executed. What event can I use to activate code when I simply tab through the field and don't necessarily edit the contents? Thanks for looking at this.
If you look at the top of the code panes, you'll notice two dropdowns. The left one contains all interfaces and event providers you can implement in that class (a UserForm is a class).
Select your MyDate control from that dropdown; the right-side dropdown is now listing every event you could handle for this MyDate control:
In this particular case, the Exit event seems a good candidate:
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'make Cancel.Value = True to prevent exiting the control.
'...ideally... make that conditional...
End Sub
By consistently using these dropdowns to let the VBE generate event handler procedures for you (instead of typing them up from memory), you avoid getting it wrong... and getting an event handler signature wrong can do anything from literally nothing at all, to compile errors if you're lucky, or weird and hard-to-diagnose behavior if you're less lucky.

Fire Subroutine when user leaves a date field ContentControl Word VBA

Edit: I've updated the post with more info.
I have a Content Control inside a header in Word in which I have a date time picker. I'm trying to fire the _ContentControlOnExit event when the user leaves the focus (blurs) of the picker.
Let's suppose I've manually created a Content Control and I've assigned it a Date Picker. I've also tagged it with the value date.
I want that each time the date is changed, I perform a subroutine that will insert a text value to another ContentControl tagged tide-level. I tried the code below with no success.
Please, note that the date ContentControl is inside a header in the Word Document.
Private Sub ActiveDocment_ContentControlOnExit(ByVal ContentControl As ContentControl, Cancel As Boolean)
If (ContentControl.Type = wdContentControlDate) Then
MsgBox "Let's do it! Write the tide levels"
dateObj = ActiveDocument.SelectContentControlsByTag("tide-level")
dateObj.Range.Text = "wwwoohooo Tide Levels!"
Cancel = True
End If
End Sub
I remember reading somewhere that whenever you have content in the header, it seems things get problematic...
Any ideas?
P.S:
Currently using Word 365 - VBA
Based on the name of the procedure in the question - ActiveDocment_ContentControlOnExit - it appears the event handler was not generated automatically by Word and that it is therefore not in the ThisDocument class module of the document that contains the content controls. The name of the event handler (generated by the VBA editor) is usually Document_ContentControlOnExit.
The content control event handlers must be in ThisDocument. Theoretically, they could be typed manually, but Word doesn't always recognize manually typed event handlers. So it's better to use the VBA Editor's automatic "stub" generation to get the structures:
Open the ThisDocument module for the document that contains the content control.
In the code page window, at the top left, select "Document" from the drop-down.
from the top-right select the event to be inserted.
At this point, the VBA editor will create the "stub" for you - all that's needed is the code to be executed.
Note about the content control being in the header: This event does fire as long as focus when exiting remains in the header. If, however, the user double-clicks in the document body in order to exit the header the event doesn't fire. (At least, not in my tests.) If this is a problem you may want to put this field in the body of the document with a second, linked content control in the header to reflect the selection. Doing this is a bit complex (requires a Custom XML Part in the document to manage the linked information), but the version of Word you're using should have a tool for setting it up.
the macro name should be:
Docment_ContentControlOnExit
NOT:
ActiveDocment_ContentControlOnExit

Programatically change selected item in Outlook

I'm trying to write a piece of code that takes a user-selected list of items (typically mailitems) from the active explorer, performs some action on them (e.g. setting the value of a custom field), then - when complete - selects the next item in the explorer window and ends execution there.
I have no problem identifying the selected list of items
I have no problem looping through the selected items and performing required actions on each
But I cannot, for the life of me, figure out how to programatically select the next item in the explorer window upon completing the above process (keeping in mind, the next item is NOT in the list of user-selected items.
Example ...
Inbox has 10 items
User selects items 1, 4 and 7
Code identifies items 1, 4 and 7 as the active selection
Code performs an action on items 1, 4 and 7
--> Upon completion, I want item #8 to be selected
Is this possible ???
The wrinkle, and why I can't just use a SendKeys "{DOWN}" statement at the end: the active view is grouped by a custom field (... call it a flag, for ease of reference) - where flag=false show up at the top of the screen in group #1, and flag=true show up in group #2 at the bottom of the screen. It's a way of relegating mailitems to a "basement" of sorts, without deleting them or having to move them to some other folder. They stay in the inbox, but get grouped separately, out of sight.
The actions being performed on items 1, 4 and 7 consist of setting the flag to TRUE, thereby causing the items to disappear from the upper portion of the screen, and moving to the lower part of the screen (i.e. in group #2). This all works great.
... until the code reaches the final item in the selection, and again does what it needs to do, and ends ... but at this point the active/selected mailitem that is displayed in the explorer window is the same last mailitem (#7). So the user is now seeing a mailitem way down the inbox in group #2. In other words, the user is now in the basement of the inbox, not at the top, because Outlook is displaying the last mailitem in the selection, which has been moved to the basement by the code.
I want the code to change the active/selected mailitem to be #8 (which still has a value of FALSE for that custom field I'm setting), so that upon completing code execution, the screen position remains where it was when the code was executed.
The only thing I've managed to do is apply a SendKeys "{HOME}" at the end, so at least the user's view continues to show the mailitems in group #1 ... but not the right mailitem.
I'm really stumped here.
Any help would be appreciated.
NB> My thought process was, at the time of initiating the code, to identify the last mailitem in the selection (... either by index # or by EntryID) - which I can do easy enough - but then somehow finding a way to i) locate the NEXT mailitem immediately following it, and storing this reference, and then ii) upon completing the code, getting outlook to select the mailitem with the reference ID I saved. I can't figure out how to do this.
Thanks
If received time is in some order you could use that to determine the next item to select.
The process could look like this.
selCount = ActiveExplorer.Selection.Count
' Assumes you select downwards not randomly
minRecTime = ActiveExplorer.Selection(selCount).ReceivedTime
Once the items are moved loop downward through the items.
currRecTime = currFolder.items(i).ReceivedTime
If currRecTime < minRecTime Then
Exit For
End If
Now you have a position with "i".
Remember to run from a button not the VB editor to see SendKeys work.
SendKeys "{HOME}"
For j = 1 To i - 1
SendKeys "{DOWN}"
Next j

MS-Word VBA reference identification

I have a custom content control in Microsoft Word from a third party I am trying to resize the width and height of. Normal content control selection via VBA is not working because this control has no Title or Tag. However, if I manually select the object and resize it programmatically using "Selection.ShapeRange.Height = x" or ShapeRange.Width it does work. So to do it all programmatically I need to determine the name of the "selection" without having to manually select it.
Is there a way to "inspect" the complete reference to the currently selected object in word, so we can then get a starting point to work with it in VBA?
It's hard to know what type of object your dealing with. I tested this by inserting a blank ActiveX image control, selecting it and then running the macro. The code has two methods but one is commented out.
Sub FindName()
MsgBox (Selection.Fields.Item(1).OLEFormat.ClassType)
'MsgBox (Selection.InlineShapes.Item(1).OLEFormat.ClassType)
MsgBox (Selection.InlineShapes.Item(1).Field.Index)
MsgBox (Selection.InlineShapes.Item(1).AlternativeText)
'Show current name
MsgBox (Selection.Fields.Item(1).OLEFormat.Object.Name)
'Set new name
Selection.Fields.Item(1).OLEFormat.Object.Name = "Image5"
'Re-display name to show that it changed
MsgBox (Selection.Fields.Item(1).OLEFormat.Object.Name)
End Sub
The result was this: