I'm using VSTO to develop add-in for Outlook.
When using Send method of MeetingItem (AppointmentItem), how can I disable Send Update to All Attendees popup? It always show when I call Send of existing meeting.
I only found ForceUpdateToAllAttendees property but it make the update send to all attendees, that would be wrong if user don't want to send updates to all attendees.
EDIT:
This is my code
void Application_ItemSend(object item, ref bool Cancel)
{
var form = new SC01(item);
form.Show();
Cancel = true; // prevent mail sending
}
...
in SC01 form:
private void btn_OK_Click(object sender, EventArgs e)
{
var meetingItem = _item As MeetingItem; // _item is private field of SC01
meetingItem.GetAssociatedAppointment(false).Send(); // this Send() will make sending option (to update attendees only or to all attendees
}
sorry I was away some days. I think I have the solution, althuogh I only "speak" vba - but in the end it is all the same...
leave away the line:
Cancel = true; // prevent mail sending
and also the line:
meetingItem.GetAssociatedAppointment(false).Send();
as far as I know the item will not be sent anyway as long as the form is not hidden again.
I hope this works!
Max
just had another idea that should solve your Problem:
void Application_ItemSend(object item, ref bool Cancel)
{
var form = new SC01(item);
form.Show();
'''next line is new and prevents the first popup
item.ForceUpdateToAllAttendees = TRUE
Cancel = true; // prevent mail sending
}
... in SC01 form:
private void btn_OK_Click(object sender, EventArgs e)
{
var meetingItem = _item As MeetingItem; // _item is private field of SC01
'''next line is new => popup Comes now
meetingItem.ForceUpdateToAllAttendees = FALSE
meetingItem.GetAssociatedAppointment(false).Send(); // this Send() will make sending option (to update attendees only or to all attendees
}
Related
I have 2 dropdowns (pickers) on a XAML form. The first is an ObservabelCollection of Territories. The second is an ObservableCollection of type Tracks. When the form loads my ViewModel loads both collections and each collection is bound to a picker. I want to filter and display only those tracks that are associated with the selected territory in the second picker.
FYI-the second picker is disabled until a selection is made in the first. Actually I don't require that the second picker's data source be set as the form loads, unless the solution requires it. The selection in the first picker will be the key to filter the data for the second.
I have tried to handle the filtering in the Territory picker's SelectedIndexChanged event but my ObservableCollection 'tracks' is not exposed here.
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
Tracks _track = tracks.Where(X => X.Territory = territory);<<<==== Does not work
trackPicker.ItemsSource = _track.Track;<<<==== Does not work
trackPicker.IsEnabled = true;
}
I've also tried to not build the Tracks OC until after the Territory is selected like this:
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
TrackViewModel vm = new TrackViewModel();
var _tracks = (Tracks)vm.Tracks; <<<<<==== This does not work
trackPicker.IsEnabled = true;
}
The ViewModel runs and the tracks are loaded via the API but when it returns here Tracks is empty.
I'm open to a reasonable solution (not 3rd party controls/packages) that will accomplish this task . Thanks
I figured it out by stumbling over the answer while researching another issue. I have been referencing my viewmodel in the {content].xaml page like this.
<ContentPage.BindingContext>
<vm:TrackViewModel />
</ContentPage.BindingContext>
When doing so the resources of that vm were not available in the code behind. But when I reference the VM in the page constructor Like this:
public partial class RequestmyTracks : ContentPage
{
TrackViewModel trackviewmodel = new TrackViewModel();
And then bind it here:
public RequestmyTracks()
{
InitializeComponent();
BindingContext = trackviewmodel;
}
The trackviewmodel is accessible in the SelectedIndexChanged event and everything else was really straight forward, Which looks like this:
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
ObservableCollection<Tracks> dah = (ObservableCollection<Tracks>)trackviewmodel.Tracks;
List<string> trackNames = new List<string>();
foreach (var track in dah)
{
if (track.Territory == territory)
trackNames.Add(track.Track);
}
trackPicker.ItemsSource = trackNames;
if(trackNames.Count ==1)
trackPicker.SelectedIndex = 0;
trackPicker.IsEnabled = true;
}
Thanks for the help
I'm programming a VSTO in Outlook 2016 and I would like to enable/disable buttons in a Ribbon, based on the user's action of START A NEW MESSAGE or just OPEN/READ a message.
My problem is HOW detect when the user pressed NEW MAIL or just open a sent/received one message.
Could anyone help me?
Thanks!
This tutorial actually deals with this exact scenario:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
inspectors = this.Application.Inspectors;
inspectors.NewInspector +=
new Microsoft.Office.Interop.Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
}
Specifically, you attach to this.Appliaction.Inspectors. The tutorial takes the opportunity to modify the Subject and Body properties of the new MailItem:
void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
Outlook.MailItem mailItem = Inspector.CurrentItem as Outlook.MailItem;
if (mailItem != null)
{
if (mailItem.EntryID == null)
{
mailItem.Subject = "This text was added by using code";
mailItem.Body = "This text was added by using code";
}
}
}
I'm trying to send emails from a .NET application using Outlook Object Model.
My application displays the Outlook message window so the user can see what we're sending and edit it first. When the user hits the Send button, the Outlook window closes, and the message gets sent. This works perfectly as long as the Outlook application is already running.
If the Outlook application isn't already running, the message gets stuck in the Outbox, and will not send until I start Outlook. When I start Outlook, I can see the message sitting in the Outbox folder for a few seconds, then it gets sent.
I need to show the New Message form to Outlook user to select the recipient(s) and possibly edit the message before sending.
Note: I know that this question was already asked here Email sent with Outlook Object Model stays in Outbox until I start Outlook
and the solution exists, but it is not provided (only the small hint is provided) and unfortunately I cannot ask for clarification / code example because I have not enough "reputation".
I tried to write my own implementation of the hint provided, but the SyncEnd event is fired only when Outlook is already open (just to remind, the question is about the case then Outlook is closed).
My code below. What is wrong?
using Microsoft.Office.Interop.Outlook;
using OutlookApp = Microsoft.Office.Interop.Outlook.Application;
class Mailer
{
AutoResetEvent mailSentEvent = new AutoResetEvent(false);
public void CreateMail()
{
OutlookApp outlookApp = null;
MailItem mailItem = null;
try
{
outlookApp = new OutlookApp();
mailItem = outlookApp.CreateItem(OlItemType.olMailItem);
mailItem.Subject = "Test Message";
mailItem.Body = "This is the message.";
string reportPath = #"C:\temp\aaaaa.pdf";
mailItem.Attachments.Add(reportPath);
mailItem.Display(true);
StartSync(outlookApp);
bool result = mailSentEvent.WaitOne();
}
catch (System.Exception)
{
throw;
}
finally
{
if (mailItem != null) Marshal.ReleaseComObject(mailItem);
if (outlookApp != null) Marshal.ReleaseComObject(outlookApp);
}
}
private static SyncObject _syncObject = null;
private void StartSync(OutlookApp outlookApp)
{
var nameSpace = outlookApp.GetNamespace("MAPI");
_syncObject = nameSpace.SyncObjects[1];
_syncObject.SyncEnd += new Microsoft.Office.Interop.Outlook.SyncObjectEvents_SyncEndEventHandler(OnSyncEnd);
_syncObject.Start();
}
private void OnSyncEnd()
{
mailSentEvent.Set();
}
}
the SyncEnd event is fired only when Outlook is already open
That is not true. The SyncObjects collection contains all Send\Receive groups. You need to iterate over all objects in the collection and call the Start method, for example:
Set sycs = nsp.SyncObjects
For i = 1 To sycs.Count
Set syc = sycs.Item(i)
strPrompt = MsgBox("Do you wish to synchronize " &; syc.Name &;"?", vbYesNo)
If strPrompt = vbYes Then
syc.Start
End If
Next
I have to add a feature in Skype for Business to open automatically a new Outlook task window when a call starts, with the phone number of the called/calling contact in the subject field. Is there any addin or api in order to do this?
Thank you
With the help of Lync SDK 2013, new conversation added event can be handled where you can also get participant related information. Inside conversation added event handler listen for AVModality state changes. When AVModality state is changed to connected, using Microsoft.Office.Interop.Outlook outlook application can be automated and new task window can be created as given below
LyncClient lyncClient = new LyncClient();
lyncClient.ConversationManager.ConversationAdded += OnConversationAdded;
private void OnConversationAdded(object sender, Microsoft.Lync.Model.Conversation.ConversationManagerEventArgs e)
{
e.Conversation.Modalities[ModalityTypes.AudioVideo].ModalityStateChanged += OnAudioVideoModalityStateChanged;
}
private void OnAudioVideoModalityStateChanged(object sender, ModalityStateChangedEventArgs e)
{
switch(e.NewState)
{
case ModalityState.Connected:
Application oOutlook = null;
oOutlook = new Application();
TaskItem oTask = (TaskItem)oOutlook.CreateItem(OlItemType.olTaskItem);
oTask.Subject = "Testing";
oTask.StartDate = DateTime.Now;
oTask.Display(true);
break;
}
}
For more information :
Microsoft.Office.Interop.Outlook,
Lync SDK 2013
I found out that it's possible to add custom task panes to individual windows like e.g. the appointment with this code snippet:
public void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
Microsoft.Office.Tools.CustomTaskPane myCustomTaskPane;
if(Inspector.CurrentItem is Microsoft.Office.Interop.Outlook.AppointmentItem ) {
UserControl uc1 = MyUserControl();
myCustomTaskPane = getAddIn().CustomTaskPanes.Add(uc1, "MyPanel",Inspector);
myCustomTaskPane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
myCustomTaskPane.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoChange;
myCustomTaskPane.Visible = true;
}
//Additionally You can add a property change listener to the current Item here
}
however, I use 'NetOffice' instead of VSTO to have the add-in compatible with various Outlook versions. And there the add-in doesn't have the CustomTaskPanes property, and the TaskPanes.Add property isn't overloaded to allow adding custom panes on other window than the main explorer.
Ok, worked it out in following way.
In the ComAddin class I have a local variable
Office._CustomTaskPane _taskPane;
and I set the variable on the overriden CTPFactoryAvailable method:
public override void CTPFactoryAvailable(object CTPFactoryInst)
{
_ctpFactory = new NetOffice.OfficeApi.ICTPFactory(this.Application, CTPFactoryInst);
}
Then - when the addin is loaded - I'm adding an event handler to the NewInspectorEvent event:
private void Addin_OnStartupComplete(ref Array custom)
{
var inspectors = Application.Inspectors as NetOffice.OutlookApi.Inspectors;
inspectors.NewInspectorEvent += Inspectors_NewInspectorEvent;
}
In the event handler for creating a new inspector window, I'm creating the pane:
private void Inspectors_NewInspectorEvent(_Inspector Inspector)
{
var ai = Inspector.CurrentItem as AppointmentItem;
if (ai == null)
return;
var ins = Inspector as NetOffice.OutlookApi.Inspector;
_taskPane = _ctpFactory.CreateCTP(typeof(Addin).Assembly.GetName().Name + ".UserControl1", "My title", Inspector);
_taskPane.DockPosition = MsoCTPDockPosition.msoCTPDockPositionTop;
_taskPane.Height = 50;
_taskPane.Visible = true;
}
This draft proof of concept works for me.