I am trying to implement Adrian Brown's very nice Outlook Add-In code and it works 2 out of 3 times. ItemAdd and ItemChange events are firing as expected, but the event handler for MAPIFolderEvents_12_Event.BeforeItemMove does not appear to be doing anything - I don't even hit a breakpoint on the first line of the event handler.
More Code for Clarity
This is the CalendarMonitor class; it monitors ItemAdd, ItemChange events on the Items collection of the folder, as well as BeforeItemMove on the MAPIFolder:
public class CalendarMonitor
{
private Explorer _explorer;
private List<string> _folderPaths;
private List<MAPIFolder> _calendarFolders;
private List<Items> _calendarItems;
private MAPIFolder _deletedItemsFolder;
public event EventHandler<EventArgs<AppointmentItem>> AppointmentAdded;
public event EventHandler<EventArgs<AppointmentItem>> AppointmentModified;
public event EventHandler<CancelEventArgs<AppointmentItem>> AppointmentDeleting;
public CalendarMonitor(Explorer explorer)
{
_folderPaths = new List<string>();
_calendarFolders = new List<MAPIFolder>();
_calendarItems = new List<Items>();
_explorer = explorer;
_explorer.BeforeFolderSwitch += Explorer_BeforeFolderSwitch;
var session = _explorer.Session;
try
{
_deletedItemsFolder = session.GetDefaultFolder(OlDefaultFolders.olFolderDeletedItems);
HookupDefaultCalendarEvents(session);
}
finally
{
Marshal.ReleaseComObject(session);
session = null;
}
}
private void HookupDefaultCalendarEvents(_NameSpace session)
{
var folder = session.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
if (folder == null) return;
try
{
HookupCalendarEvents(folder);
}
finally
{
Marshal.ReleaseComObject(folder);
folder = null;
}
}
private void Explorer_BeforeFolderSwitch(object obj, ref bool cancel)
{
var folder = (obj as MAPIFolder);
if (folder == null) return;
try
{
// Hookup events to any other Calendar folder opened.
if (folder.DefaultItemType == OlItemType.olAppointmentItem)
HookupCalendarEvents(folder);
}
finally
{
Marshal.ReleaseComObject(folder);
folder = null;
}
}
private void HookupCalendarEvents(MAPIFolder calendarFolder)
{
if (calendarFolder.DefaultItemType != OlItemType.olAppointmentItem)
{
throw new ArgumentException("The MAPIFolder must use AppointmentItems as the default type.");
}
// Ignore other user's calendars.
if (_folderPaths.Contains(calendarFolder.FolderPath) || (!IsUsersCalendar(calendarFolder))) return;
var items = calendarFolder.Items;
// Store folder path to prevent repeating listeners
_folderPaths.Add(calendarFolder.FolderPath);
// Store a reference to the folder & items to prevent garbage collection
_calendarFolders.Add(calendarFolder);
_calendarItems.Add(items);
// Add listeners
((MAPIFolderEvents_12_Event)calendarFolder).BeforeItemMove += Calendar_BeforeItemMove;
items.ItemChange += CalendarItems_ItemChange;
items.ItemAdd += CalendarItems_ItemAdd;
}
private void CalendarItems_ItemAdd(object obj)
{
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
if (AppointmentAdded != null)
AppointmentAdded(this, new EventArgs<AppointmentItem>(appointment));
}
finally
{
Marshal.ReleaseComObject(appointment);
appointment = null;
}
}
private void CalendarItems_ItemChange(object obj)
{
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
if (AppointmentModified != null)
AppointmentModified(this, new EventArgs<AppointmentItem>(appointment));
}
finally
{
Marshal.ReleaseComObject(appointment);
appointment = null;
}
}
private void Calendar_BeforeItemMove(object obj, MAPIFolder moveToFolder, ref bool cancel)
{
if ((moveToFolder != null) && (!IsDeletedItemsFolder(moveToFolder))) return;
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
if (AppointmentDeleting == null) return;
// Listeners to the AppointmentDeleting event can cancel the move operation if moving
// to the deleted items folder.
var args = new CancelEventArgs<AppointmentItem>(appointment);
AppointmentDeleting(this, args);
cancel = args.Cancel;
}
finally
{
Marshal.ReleaseComObject(appointment);
appointment = null;
}
}
private bool IsUsersCalendar(MAPIFolder folder)
{
// This is based purely on my observations so far - a better way?
return (folder.Store != null);
}
private bool IsDeletedItemsFolder(MAPIFolder folder)
{
return (folder.EntryID == _deletedItemsFolder.EntryID);
}
public AppointmentItem Item { get; set; }
}
New Information:
I have done some additional "troubleshooting" and come up with more information: on a whim, I created a new calendar in Outlook (while debugging) and lo and behold the BeforeItemMove event fires just like I expect it to when deleting an appointment in the new calendar, but it still doesn't work in the original.
If I exit the debug session and restart, neither calendar's event functions as expected, despite working fine earlier. Any new calendar's BeforeItemMove event will work fine, until I close Outlook - then it's back to not responding.
I am hoping that this additional information will provide insight to those wiser than I. Any assistance is greatly appreciated.
calFolder variable must be declared on the global/class level to avoid being released by the Garbage Collector.
Where did you declare the source object? Is it alive when the event should be fired?
Anyway, you may consider developing an inspector wrapper. See Developing an Inspector Wrapper for Outlook 2010 and How to: Implement a Wrapper for Inspectors and Track Item-Level Events in Each Inspector for more information.
The sample project in C# and VB.NET is also available - Outlook 2010: Developing an Inspector Wrapper.
Related
I have a button connected to the start and stop below. After a number of button clicks the application hangs on Trace.Listeners.Remove(_listener). Any idea why?
public void StartListener(ITraceTextSink sink)
{
if (_listener != null) return;
_listener = new TraceSource(sink);
Trace.AutoFlush = true;
Trace.Listeners.Add(_listener);
}
public void StopListener()
{
if (_listener == null) return;
Trace.Listeners.Remove(_listener);
_listener.Dispose();
_listener = null;
}
I'm writing a little extension for Visual Studio 2015.
I added a VSPackage to to embed some CustomCommands on the Shortcut Menu you get when you RightClick on a Project or a Folder inside the Solution Explorer.
What I would like to do now is "open the Add New Item dialog and select the one of the templates I've installed with this VSPackage".
This is the Code I use to initialize my commands:
private TemplateCommand(Package package)
{
if (package == null)
throw new ArgumentNullException(nameof(package));
_package = package;
var commandService = ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService == null)
return;
AddCommand(commandService, CommandId, CreateCustomTemplate);
}
The CreateCustomTemplate callback code is this:(for the moment I simply create a messageBox, just to ensure it works)
private void CreateCustomTemplate(object sender, EventArgs eventArgs)
{
//TODO: code to replace!
var message = string.Format(CultureInfo.CurrentCulture, "Inside {0}.CreateCustomTemplate()", GetType().FullName);
// Show a message box to prove we were here
VsShellUtilities.ShowMessageBox(
ServiceProvider,
message,
"CREATE CustomTemplate",
OLEMSGICON.OLEMSGICON_INFO,
OLEMSGBUTTON.OLEMSGBUTTON_OK,
OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
}
So, to recap, how do I open the Add New Item dialog box and select a specific item template?
As an example, when you try to create a Class or a UserControl right-clicking on a folder in the solution explorer
You obtain something similar to this:
And this is, exactly, what I'm trying to achieve. Obviously I would like to create my own template and not the UserControl.
If you need any clarification feel free to ask.
Thank you in advance for any suggestion
In the end I resolved my problem.
Unfortunately the command File.AddNewItem (or Project.AddNewItem) is not suitable in my case as I want to see the AddNewFile Dialog (and these command simply adds the item to the specified project).
I Found the solution digging the web, exactly here, specifically thanks to the answer of Vladimir.Ilic.
This is the code I use to achieve my goal:
internal sealed class TemplateCommand
{
private const int CustomCommandId = 0x1023;
private static readonly Guid CommandSet = COMMANDSET_GUID;
private readonly Package _package;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
public IServiceProvider ServiceProvider => _package;
public static TemplateCommand Instance { get; set; }
// ReSharper restore UnusedAutoPropertyAccessor.Global
// ReSharper restore MemberCanBePrivate.Global
public static void Initialize(Package package)
{
Instance = new TemplateCommand(package);
}
private TemplateCommand(Package package)
{
if (package == null)
throw new ArgumentNullException(nameof(package));
_package = package;
var commandService = ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService == null)
return;
AddCommand(commandService, CustomCommandId, CreateCustomCommand);
}
private static void AddCommand(IMenuCommandService commandService, int commandId, EventHandler callback)
{
var command = new CommandID(CommandSet, commandId);
var menuItem = new MenuCommand(callback, command);
commandService.AddCommand(menuItem);
}
private void CreateCustomCommand(object sender, EventArgs eventArgs)
{
AddNewItem("MyCustomCommand");
}
private void AddNewItem(string itemName)
{
var dte = ServiceProvider.GetService(typeof(DTE)) as DTE;
if (dte == null)
return;
int iDontShowAgain;
uint projectItemId;
var strFilter = string.Empty;
var hierarchy = GetCurrentVsHierarchySelection(out projectItemId);
if (hierarchy == null)
return;
var project = ToDteProject(hierarchy);
if (project == null)
return;
var vsProject = ToVsProject(project);
if (vsProject == null)
return;
var addItemDialog = ServiceProvider.GetService(typeof(IVsAddProjectItemDlg)) as IVsAddProjectItemDlg;
if (addItemDialog == null)
return;
const uint uiFlags = (uint)(__VSADDITEMFLAGS.VSADDITEM_AddNewItems | __VSADDITEMFLAGS.VSADDITEM_SuggestTemplateName | __VSADDITEMFLAGS.VSADDITEM_AllowHiddenTreeView);
const string categoryNameInNewFileDialog = "MyCustomTemplates";
// ProjectGuid for C# projects
var projGuid = new Guid("FAE04EC0-301F-11D3-BF4B-00C04F79EFBC");
string projectDirectoryPath;
hierarchy.GetCanonicalName(projectItemId, out projectDirectoryPath);
var itemNameInNewFileDialog = itemName;
addItemDialog.AddProjectItemDlg(projectItemId,
ref projGuid,
vsProject,
uiFlags,
categoryNameInNewFileDialog,
itemNameInNewFileDialog,
ref projectDirectoryPath,
ref strFilter,
out iDontShowAgain);
}
private static IVsHierarchy GetCurrentVsHierarchySelection(out uint projectItemId)
{
IntPtr hierarchyPtr, selectionContainerPtr;
IVsMultiItemSelect mis;
var monitorSelection = (IVsMonitorSelection)Package.GetGlobalService(typeof(SVsShellMonitorSelection));
monitorSelection.GetCurrentSelection(out hierarchyPtr, out projectItemId, out mis, out selectionContainerPtr);
var hierarchy = Marshal.GetTypedObjectForIUnknown(hierarchyPtr, typeof(IVsHierarchy)) as IVsHierarchy;
return hierarchy;
}
private static Project ToDteProject(IVsHierarchy hierarchy)
{
if (hierarchy == null)
throw new ArgumentNullException(nameof(hierarchy));
object prjObject;
if (hierarchy.GetProperty(0xfffffffe, (int)__VSHPROPID.VSHPROPID_ExtObject, out prjObject) == VSConstants.S_OK)
return (Project)prjObject;
throw new ArgumentException("Hierarchy is not a project.");
}
private IVsProject ToVsProject(Project project)
{
if (project == null)
throw new ArgumentNullException(nameof(project));
var vsSln = ServiceProvider.GetService(typeof(IVsSolution)) as IVsSolution;
if (vsSln == null)
throw new ArgumentException("Project is not a VS project.");
IVsHierarchy vsHierarchy;
vsSln.GetProjectOfUniqueName(project.UniqueName, out vsHierarchy);
// ReSharper disable SuspiciousTypeConversion.Global
var vsProject = vsHierarchy as IVsProject;
// ReSharper restore SuspiciousTypeConversion.Global
if (vsProject != null)
return vsProject;
throw new ArgumentException("Project is not a VS project.");
}
}
Big thanks to the ones that passed by and that have tried (or even thinked) to help!
Hope this helps someone,
Sincerely
You can execute the commands "Project.AddNewItem" or "File.AddNewItem" to show the dialog. There are several ways to execute a command programmatically, the easiest is to get the EnvDTE.DTE instance and call dte.ExecuteCommand(commandName).
As for selecting the desired template, see the parameters for the command File.AddNewItem. With some luck the are the same for the Project.AddNewItem command.
I'am creating MailItem:
Application outlook = new Application();
_mailItem = outlook.CreateItem(OIItemType.olMailItem);
Inspector inspector = _mailItem .GetInspector;
inspector.Activate();
set recipient, body, etc...
Subscribe to an send event:
((ItemEvents_10_Event)_mailItem).Send += MailItemSendHandler;
void MailItemSendHandler(ref bool isSended) {
_mailItem.SaveAs(filePath);
}
When a user sent the email, I save it. But my email saved in compose mode. If i will open it in OutLook, i can change all information and i can resend it.
If i subscribe to the MailItem Inspector close event:
((InsPectorsEvents_10_Event)inspector).Close += CloseEventHandler;
and saving MailItem in CloseEventHandler, i have an error:
"Item has been moved or deleted".
How can i save my MailItem after it will be sended and moved in "Sent items" Outlook folder? (save in read mode)
EDIT
I'am using Items.AddItem event for saving my sent _mailItem. Get folder:
_sentFolderItems = _mailItem.SaveSentMessageFolder;
subscribe with some logic in _addEventHandler:
_sentFolderItems.Items.ItemAdd += _addEventHandler;
Good:
Outlook main window is running.
Outlook process is displayed in task manager.
I'am generating MailItem, showing it for user. User make some changes if he wish, and press send button.
4. Items.ItemAdd is fired and _addEventHandler is executed.
Outlook mail window is still running, and outlook process is displayed in task manager.
Bad:
Outlook main window is not running, and there is no process in task manager.
I'am generating MailItem, show it for user. There is only window for sending email displayed for user. Outlook process is displayed in task manager. User make some changes if he wish, and press send button. Mail is sended and task Manager does'nt have a OutLook process.
Items.ItemAdd is NOT fired and _addEventHandler is NOT executed.
But of corse sent item is located in sent folder.
public class MailItemWrapper {
public MailItemWrapper(MailItem mailItem, ComposeEmailWrapper composeEmailWrapper, bool isCompose) {
_mailItem = mailItem;
_identifyProperty = Guid.NewGuid();
_mailItem.AddUserProperty(_identifyProperty.ToString(), _identifyProperty.ToString());
_sentFolderItems = _mailItem.SaveSentMessageFolder;
_inspector = _mailItem.GetInspector;
_composeEmailWrapper = composeEmailWrapper;
InComposeMode = isCompose;
SetEventHandlers();
Subscribe();
_isSending = false;
}
private MailItem _mailItem;
private Inspector _inspector;
private MAPIFolder _sentFolderItems;
private InspectorEvents_10_CloseEventHandler _closeEventHandler;
private ItemEvents_10_SendEventHandler _sendEventHandler;
private ItemsEvents_ItemAddEventHandler _addEventHandler;
private readonly ComposeEmailWrapper _composeEmailWrapper;
private string _path;
private bool _isSending;
private Guid _identifyProperty;
public bool InComposeMode {
get; set;
}
public MailItem MailItem {
get {
return _mailItem;
}
}
public void Subscribe() {
((ItemEvents_10_Event) _mailItem).Send += _sendEventHandler;
((InspectorEvents_10_Event) _inspector).Close += _closeEventHandler;
_sentFolderItems.Items.ItemAdd += _addEventHandler;
}
public void UnsubscribeAndRelease() {
if(InComposeMode) {
((ItemEvents_10_Event) _mailItem).Send -= _sendEventHandler;
((InspectorEvents_10_Event) _inspector).Close -= _closeEventHandler;
_sentFolderItems.Items.ItemAdd -= _addEventHandler;
Marshal.ReleaseComObject(_sentFolderItems);
Marshal.ReleaseComObject(_mailItem);
Marshal.ReleaseComObject(_inspector);
_sentFolderItems = null;
_mailItem = null;
_inspector = null;
InComposeMode = false;
_isSending = false;
}
}
private void SetEventHandlers() {
_sendEventHandler = (ref bool cancel) =>{
_isSending = true;
};
_addEventHandler = delegate (object item) {
var mailItem = item as MailItem;
if(mailItem != null) {
var identityer = mailItem.UserProperties.Find(_identifyProperty.ToString());
if(identityer != null && _identifyProperty.ToString() == identityer.Value) {
_path = mailItem.SaveAsInTempFolder(); // extension
if(_composeEmailWrapper != null && _composeEmailWrapper.Callback != null) {
System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (System.Action) ExecuteCallBack);
UnsubscribeAndRelease();
}
}
Marshal.ReleaseComObject(mailItem);
}
};
_closeEventHandler = () => {
// if user close dialog without sending => unsibscribe
if(!_isSending) {
UnsubscribeAndRelease();
}
};
}
private void ExecuteCallBack() {
_composeEmailWrapper.Callback(_path, _composeEmailWrapper.SessionId);
}
}
use Items.ItemAdd event on the Sent Items folder.
Outlook 2016
.Net Framework 4.5
i encounter a really strange behaviour:
when i iterate through the items collection of a contact folder in some very special undefined cases (which i do not really understand) some userproperties of the first item of the collection fail to load. However the UserProperties are definitly set.
The approach is following:
I open the contact folder (to which the items will be moved) in outlook.
then i execute the "test"
the execution of the test can be suammrized as following:
click button ->
start thread
iterate through the items (on first iteration no items are present).
add new items{
create item
set userproperty PRE before item is initially saved
save item
move item to desired folder
set userproperty POST after item is moved
save item
}
end thread
click button ->
start thread
iterate through the items (here the userproperty POST sometimes fails to load on the first item of the collection, however when i investigate it, it IS there. It only fails for the first item and succeeds for every other following item).
...END
it seems to me that outlook somehow fails to update the userproperty definitions timely. But note that the first BackgroundWorker thread is already finished when iterating through the items with the second backgroundworker thread.
The problem could be related to the fact that iam viewing the folder in the explorer while the items are added and iterated.
This bug is hard to reproduce and does only occur rarely.
however i'm really missing insight into the inner workings of outlook so i can only speculate.
Idea for workarounds:
I could add an item with all userproperties before moving it. the problem here is that i need to add new userproperties, after the item is initially saved and moved to the folder, in some scenarios.
in few cases the userproperty key is dynamically created (with a pattern) so it wouldn't be optimal to predefine all userproperties.
It's very important that the userProperties are reliably loaded because some important features are based upon them.
Does anybody has a clue how the problem is caused and how to solve it? because this behaviour is driving me crazy.
some Code (not the original but it should contain all the relevant aspects)
//Ribbon
TestNS.TestCaller testCaller;
string folderID = "00000000BDB409934ED327439481EB6E1E1CC4D3010055B62301B58E32478DCD8C0D3FA6304600002C4CA4400000";
public void testButton0_Action(Office.IRibbonControl control)
{
if(testCaller == null){
testCaller = new TestNS.TestCaller(ThisAddIn.Outlook,folderID);
}
testCaller.Run();
}
//Ribbon end
using System.Runtime.InteropServices;
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
namespace TestNS
{
public class TestCaller{
private Outlook.Application application;
private BackgroundWorker worker = new BackgroundWorker();
private Test test = null;
private string folderId;
private bool init = true;
private bool busy = false;
public TestCaller(Outlook.Application application, string folderId){
this.application = application;
this.folderId = folderId;
worker.DoWork += new DoWorkEventHandler(DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnCompleted);
}
public void Run()
{
if (!busy)
{
busy = true;
test = new Test(application, folderId, init);
worker.RunWorkerAsync();
}
}
private void DoWork(object sender, DoWorkEventArgs e)
{
test.Process();
test = null;
}
private void OnCompleted(object sender, RunWorkerCompletedEventArgs e)
{
busy = false;
init = false;
}
}
class Test
{
public const string key_preCreateProperty ="preCreate";
public const string key_postCreateProperty = "postCreate";
private Outlook.Application application;
private string folderId;
private bool createData;
public Test(Outlook.Application application,string folderId,bool createData)
{
this.application = application;
this.folderId = folderId;
this.createData = createData;
}
public void Process(){
Examine();
if(createData){
CreateData();
}
}
public void CreateData()
{
List<Poco> pocos = new List<Poco>();
for (int i = 0; i < 10; i++)
{
pocos.Add(
new Poco
{
Pre = "Pre" + i,
Post = "Post" + i
}
);
}
CreateContactItems(folderId,pocos);
}
public void Examine()
{
bool preIsLoaded = false;
bool postIsLoaded = false;
Debug.WriteLine(">>>Examine");
Outlook.MAPIFolder folder = application.Session.GetFolderFromID(folderId);
Outlook.Items folderItems = folder.Items;
int i = 0;
//print UserProperties registered to the items
foreach(Outlook.ContactItem contactItem in folderItems){
var itemUserProperties = contactItem.UserProperties;
string itemUserPropertiesString = "";
foreach (var itemProp in itemUserProperties)
{
Outlook.UserProperty prop = (Outlook.UserProperty)itemProp;
itemUserPropertiesString += " " +prop.Name + " " + prop.Value + " \n";
}
//HERE: sometimes it prints only Pre on the first index of the iteration
Debug.WriteLine(string.Format("i={0} , itemUserProperties Count={1} , following UserProperties: \n{2}", i++, itemUserProperties.Count, itemUserPropertiesString));
string pre = null;
string post = null;
try
{
pre = contactItem.GetUserProperty(key_preCreateProperty);
preIsLoaded = true;
}
catch(KeyNotFoundException ex){
Debug.WriteLine("Error: Pre Not found"); //should not happen - doesn't happen
}
try
{
post = contactItem.GetUserProperty(key_postCreateProperty);
postIsLoaded = true;
}
catch (KeyNotFoundException ex)
{
Debug.WriteLine("Error: Post Not found"); //shoul not happen - happens rarely totally indeterminitic
}
Marshal.ReleaseComObject(itemUserProperties);
}
Debug.WriteLine("<<<Examine");
if (folderItems.Count > 0 && (!preIsLoaded || !postIsLoaded))
{
MessageBox.Show("preIsLoaded="+preIsLoaded +" \n" +"postIsLoaded="+postIsLoaded);
}
Marshal.ReleaseComObject(folderItems);
Marshal.ReleaseComObject(folder);
}
public void CreateContactItems(string folderId,List<Poco> pocos)
{
Outlook.MAPIFolder folder = application.Session.GetFolderFromID(folderId);
foreach(Poco poco in pocos){
CreateContactItem(folder,poco);
}
Marshal.ReleaseComObject(folder);
}
public void CreateContactItem(Outlook.MAPIFolder testFolder,Poco data)
{
Outlook.ContactItem contactItem = application.CreateItem(Outlook.OlItemType.olContactItem);
contactItem.SetUserProperty(key_preCreateProperty, data.Pre);
contactItem.Save();
Outlook.ContactItem movedContactItem = (Outlook.ContactItem)contactItem.Move(testFolder);
Marshal.ReleaseComObject(contactItem);
contactItem = movedContactItem;
contactItem.FirstName = data.Pre;
contactItem.LastName = data.Post;
contactItem.SetUserProperty(key_postCreateProperty, data.Post);
contactItem.Save();
Marshal.ReleaseComObject(contactItem);
}
}
public static class Util
{
public static void SetUserProperty(this Outlook.ContactItem item, string name, dynamic value)
{
Outlook.UserProperty property = item.UserProperties[name];
if (property == null)
{
property = item.UserProperties.Add(name, Outlook.OlUserPropertyType.olText);
}
property.Value = value;
}
public static dynamic GetUserProperty(this Outlook.ContactItem item, string name)
{
Outlook.UserProperty property = item.UserProperties[name];
if (property != null)
{
return property.Value;
}
throw new KeyNotFoundException(string.Format("UserProperty name={0} not found", name));
}
}
public class Poco
{
public string Pre
{
get;
set;
}
public string Post
{
get;
set;
}
}
}
Thank you for any replies
Outlook Object Model cannot be used on a secondary thread within a COM addin. Outlook 2016 will raise an exception as soon as it detects an OOM object being accessed on a secondary thread.
In fear of asking a question that might have been asked before, but my search skills did not able me to find. Okay, so here goes.
I have Windows Phone 8 App, where I can receive TileUpdates and Notifications, when My app is not running in the foreground. This I did by following http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202940(v=vs.105).aspx
In that link I learned that for getting notifications when app is running I should simply attach an event for the reception case. This I did in my AcquirePushChannel() function, which looks as follows:
public static void AcquirePushChannel()
{
CurrentChannel = HttpNotificationChannel.Find("MyPushChannel");
if (CurrentChannel == null)
{
CurrentChannel = new HttpNotificationChannel("MyPushChannel");
CurrentChannel.Open();
if (!CurrentChannel.IsShellToastBound)
{
CurrentChannel.BindToShellTile();
}
CurrentChannel.BindToShellToast();
CurrentChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(Push_NotificationRecieved);
}
if (!CurrentChannel.IsShellTileBound)
{
CurrentChannel.BindToShellToast();
CurrentChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(Push_NotificationRecieved);
}
CurrentChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(Push_NotificationChannelChanged);
}
I have implemented CurrentChannel.ChannelUriUpdated, for the case that channelUri changes and I execute some code to also changes my ChannelsTable in the Cloud.
My Push_NotificationRecieved looks like:
private static void Push_NotificationRecieved(object sender, NotificationEventArgs e)
{
StringBuilder message = new StringBuilder();
string relativeUri = string.Empty;
message.AppendFormat("Received Toast {0}:\n", DateTime.Now.ToShortTimeString());
// Parse out the information that was part of the message.
foreach (string key in e.Collection.Keys)
{
message.AppendFormat("{0}: {1}\n", key, e.Collection[key]);
if (string.Compare(
key,
"wp:Param",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.CompareOptions.IgnoreCase) == 0)
{
relativeUri = e.Collection[key];
}
}
// Display a dialog of all the fields in the toast.
MessageBox.Show(message.ToString());
//Dispatcher.BeginInvoke((message) => MessageBox.Show(message.ToString()));
}
I cannot see why the notification is not registered. Since in my log in the cloud I receive that the Toast Notification was received?
Any Ideas? Furthermore can I display the toast from the code or something similar, as far as I have read it is not possible?
Extra
Have tried changing the functions to public but did not help with the problem.
Anybody have an Idea to why the event is not firing.
The answer you posted is almost correct. From the previous you have:
public static void AcquirePushChannel()
{
CurrentChannel = HttpNotificationChannel.Find("MyPushChannel");
if (CurrentChannel == null)
{
CurrentChannel = new HttpNotificationChannel("MyPushChannel");
CurrentChannel.Open();
if (!CurrentChannel.IsShellToastBound)
{
CurrentChannel.BindToShellTile();
}
CurrentChannel.BindToShellToast();
}
if (!CurrentChannel.IsShellTileBound)
{
CurrentChannel.BindToShellToast();
}
CurrentChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(Push_NotificationChannelChanged);
CurrentChannel.ShellToastNotificationReceived += CurrentChannel_ShellToastNotificationReceived;
}
And to that you have to add:
private static void CurrentChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
{
StringBuilder message = new StringBuilder();
string relativeUri = string.Empty;
message.AppendFormat("Received Toast {0}:\n", DateTime.Now.ToShortTimeString());
// Parse out the information that was part of the message.
foreach (string key in e.Collection.Keys)
{
message.AppendFormat("{0}: {1}\n", key, e.Collection[key]);
if (string.Compare(
key,
"wp:Param",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.CompareOptions.IgnoreCase) == 0)
{
relativeUri = e.Collection[key];
}
}
// Display a dialog of all the fields in the toast.
MessageBox.Show(message.ToString());
}
So all you send is inside the e.collection. So you can from the server send all kind of parameters.
Of course just after I set a bounty to run I got it working. So here is the updated code.
public static void AcquirePushChannel()
{
CurrentChannel = HttpNotificationChannel.Find("MyPushChannel");
if (CurrentChannel == null)
{
CurrentChannel = new HttpNotificationChannel("MyPushChannel");
CurrentChannel.Open();
if (!CurrentChannel.IsShellToastBound)
{
CurrentChannel.BindToShellTile();
}
CurrentChannel.BindToShellToast();
}
if (!CurrentChannel.IsShellTileBound)
{
CurrentChannel.BindToShellToast();
}
CurrentChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(Push_NotificationChannelChanged);
CurrentChannel.ShellToastNotificationReceived += CurrentChannel_ShellToastNotificationReceived;
}
Okay so the reason for this, is that you need to set the events on every startup. Then you will get the wished properties. Then you have to create your own code for getting what you want :)