DXOutlook365Sync Class
A component that allows you to synchronize user appointments in WinForms Scheduler/WPF Scheduler with Outlook 365 Calendars (bi-directionally).
Namespace: DevExpress.XtraScheduler.Microsoft365Calendar
Assembly: DevExpress.XtraScheduler.v24.1.Microsoft365Calendar.dll
NuGet Package: DevExpress.Scheduler.Core.Desktop.Microsoft365Calendar
Declaration
Remarks
Examples
The following GitHub examples demonstrate how to synchronize user appointments with Microsoft 365 calendars (import, export, merge):
- WinForms Scheduler - Synchronize User Appointments with Microsoft 365 Calendars
- WPF Scheduler - Synchronize User Appointments with Microsoft 365 Calendars
Get Started
Install the following dependency libraries (NuGet packages):
Then add the DXOutlook365Sync
component to the project.
Use the Scheduler smart tag menu to add DXOutlook365Sync
to the project. The Sync with Microsoft 365 Calendar menu item is not displayed if the required dependency libraries are not installed. DXOutlook365Sync
automatically fills its Storage after it is created.
Note
The “Sync with Microsoft 365 Calendar” smart tag menu item is not available for .NET 6+ applications.
Add the DXOutlook365Sync
component to the project as follows. Note that you need to use a SchedulerControl.CreateStorageAdapter
method to fill the component’s Storage.
using DevExpress.Xpf.Scheduling;
using DevExpress.XtraScheduler.Microsoft365Calendar;
// ...
public partial class MainWindow : Window {
DXOutlook365Sync dXOutlook365Sync;
public MainWindow() {
InitializeComponent();
dXOutlook365Sync = new DXOutlook365Sync(uiScheduler.CreateStorageAdapter());
//...
}
// ...
}
Initialize DXOutlook365Sync
Important
You must initialize the DXOutlook365Sync
component before using its API. Otherwise, the DXOutlook365Sync
component throws an exception.
Call the InitAsync method to initialize the DXOutlook365Sync
component. The method opens a Sign in to your account window that requires you to log in to Microsoft 365.
The DXOutlook365Sync
component requires that you register your application in Azure as demonstrated in the following topic: Register an application with the Microsoft identity platform. After the registration, you can use one of the techniques below to pass registration data to the DXOutlook365Sync
component:
- Pass tenant and client IDs to the InitAsync(String, String) method.
- Create an instance of the OutlookEngine class with specified tenant and client IDs or
Azure.Core.TokenCredential
and pass this instance to the DXOutlook365Sync(ISchedulerStorageBase, IOutlookEngine) constructor or InitAsync(IOutlookEngine) method. - Specify a class that implements the IOutlookEngine interface and pass the class instance to the DXOutlook365Sync(ISchedulerStorageBase, IOutlookEngine) constructor or InitAsync(IOutlookEngine) method.
The InitAsync
method returns an InitStatus enumeration value that indicates whether the initialization succeeded, failed, or has already been initialized. The InitAsync
method does nothing if the DXOutlook365Sync
component has already been initialized.
The following example demonstrates how to create and initialize the DXOutlook365Sync
component:
using DevExpress.XtraScheduler.Microsoft365Calendar;
DXOutlook365Sync dxOutlook365Sync1;
public Form1() {
InitializeComponent();
// Install the required dependency libraries before using the DXOutlook365Sync component.
dxOutlook365Sync1 = new DXOutlook365Sync(schedulerDataStorage1);
// Initializes the 'dxOutlook365Sync1' component.
string tenantId = "..."; // Enter your tenant (directory) ID.
string clientId = "..."; // Enter your client (application) ID.
InitStatus status = await outlook365sync.InitAsync(tenantId, clientId);
// Returns false and displays a message box if the initialization of 'dxOutlook365Sync1' failed.
if(status == InitStatus.Error)
XtraMessageBox.Show("Initialization of DXOutlook365Sync failed.", "Error", MessageBoxButtons.OK);
}
The DXOutlook365Sync
component raises the InitComplete event once its initialization is finished (see the following example). The e.InitStatus
parameter specifies whether the initialization succeeded or failed. Use the e.Exception
property to get the description of the exception.
private void DxOutlook365Sync1_InitComplete(object sender, InitCompleteEventArgs e) {
if(e.InitStatus == InitStatus.Error)
XtraMessageBox.Show(String.Format("Initialization of DXOutlook365Sync failed. {0}", e.Exception.Message), "Error", MessageBoxButtons.OK);
}
Microsoft 365 Calendars
The DXOutlook365Sync
component automatically populates its Calendars collection if the initialization was successful. This collection contains OutlookCalendarItem objects that correspond to Office365 calendars.
A calendar (OutlookCalendarItem) has the EnableSynchronization option that specifies whether to synchronize its events with user appointments in the Scheduler control.
Enable or Disable Synchronization for Calendars
The DXOutlook365Sync
component includes the following methods to enable or disable synchronization for calendars:
- EnableCalendar(String) — Enables synchronization for the specified calendar and disables synchronization for other calendars.
- EnableAllCalendars() — Enables synchronization for all calendars.
Reload Calendars
Use the SynchronizeCalendarsAsync() method to force the DXOutlook365Sync
component to synchronize (reload) its Calendars collection with Microsoft 365 calendars.
The DXOutlook365Sync
component raises the CalendarSynchronizeComplete event when the calendar synchronization is complete. Use the e.Exception
event parameter to get a description of the error if the operation failed.
Import Microsoft 365 Events
The ImportOutlookToSchedulerAsync(Boolean) method imports events from Microsoft 365 calendars with synchronization enabled.
This example demonstrates how to import events from all Outlook 365 calendars to the WinForms Scheduler control.
using DevExpress.XtraScheduler.Microsoft365Calendar;
DXOutlook365Sync dxOutlook365Sync1;
public Form1() {
InitializeComponent();
dxOutlook365Sync1 = new DXOutlook365Sync(schedulerDataStorage1);
dxOutlook365Sync1.InitComplete += DxOutlook365Sync1_InitComplete;
}
private async Task<bool> InitOutlook365Sync(DXOutlook365Sync outlook365sync) {
// Initializes the 'dxOutlook365Sync1' component.
string tenantId = "..."; // Enter your tenant (directory) ID.
string clientId = "..."; // Enter your client (application) ID.
InitStatus status = await outlook365sync.InitAsync(tenantId, clientId);
// Returns false and displays a message box if the initialization of 'dxOutlook365Sync1' failed.
if(status == InitStatus.Error) {
XtraMessageBox.Show("Initialization of DXOutlook365Sync failed.", "Error", MessageBoxButtons.OK);
return false;
}
return true;
}
private async void importEventsButton_Click(object sender, EventArgs e) {
// Checks whether the initialization of 'dxOutlook365Sync1' failed.
if(!await InitOutlook365Sync(dxOutlook365Sync1)) return;
// Displays the wait form.
splashScreenManager1.ShowWaitForm();
// Imports Outlook 365 events to the Scheduler control.
await dxOutlook365Sync1.ImportOutlookToSchedulerAsync(false);
// Hides the wait form.
splashScreenManager1.CloseWaitForm();
}
Export User Appointments
The ExportSchedulerToOutlookAsync(Boolean) method exports the appointments from the Scheduler control to the Office365 calendars with synchronization enabled. Appointments that do not have corresponding events in Microsoft 365 are exported to the default calendar in Office365.
using DevExpress.XtraScheduler.Microsoft365Calendar;
DXOutlook365Sync dxOutlook365Sync1;
public Form1() {
InitializeComponent();
dxOutlook365Sync1 = new DXOutlook365Sync(schedulerDataStorage1);
dxOutlook365Sync1.InitComplete += DxOutlook365Sync1_InitComplete;
}
private async Task<bool> InitOutlook365Sync(DXOutlook365Sync outlook365sync) {
// Initializes the 'dxOutlook365Sync1' component.
string tenantId = "..."; // Enter your tenant (directory) ID.
string clientId = "..."; // Enter your client (application) ID.
InitStatus status = await outlook365sync.InitAsync(tenantId, clientId);
// Returns false if the initialization of 'dxOutlook365Sync1' failed.
return status != InitStatus.Error;
}
private async void exportAppointmentsButton_Click(object sender, EventArgs e) {
// Checks whether the initialization of 'dxOutlook365Sync1' failed.
if(!await InitOutlook365Sync(dxOutlook365Sync1)) return;
splashScreenManager1.ShowWaitForm();
// Exports the Scheduler control's appointments to Outlook365.
await dxOutlook365Sync1.ExportSchedulerToOutlookAsync(false);
splashScreenManager1.CloseWaitForm();
}
private void DxOutlook365Sync1_InitComplete(object sender, InitCompleteEventArgs e) {
if(e.InitStatus == InitStatus.Error)
XtraMessageBox.Show(String.Format("Initialization of DXOutlook365Sync failed. {0}", e.Exception.Message), "Error", MessageBoxButtons.OK);
}
Merge Calendars
Use the following methods to merge the Scheduler control with Microsoft 365 calendars:
Skip Unwanted Appointments and Events
Handle the MergeSingleItem event to specify a merge action based on a condition. The MergeSingleItem
event occurs for each appointment/event pair during an export, an import, or a merge operation and allows you to redefine a merge action based on a condition.
Use the e.ActionType property to specify the merge action.
The following example demonstrates how to import Outlook 365 events that have not started.
using DevExpress.XtraScheduler.Microsoft365Calendar;
dxOutlook365Sync1.MergeSingleItem += DxOutlook365Sync1_MergeSingleItem;
private void DxOutlook365Sync1_MergeSingleItem(object sender, Outlook365CalendarMergeEventArgs e) {
if(e.OutlookEvent != null && e.OutlookEvent.Start.ToDateTime() < DateTime.Now)
e.ActionType = MergeActionType.DoNothing;
}
Resolve Merge Conflicts
If you make conflicting edits to a Scheduler appointment and an Microsoft 365 event, the DXOutlook365Sync
component is unable to identify which of these objects holds valid data. The component raises the MergeConflictResolve event to allow you to resolve a merge conflict.
Handle the MergeConflictResolve
event and set the e.ActionType
parameter to MergeActionType.InsertOrUpdateEvent
to copy a Scheduler appointment to a Microsoft 365 calendar. Otherwise, set the parameter to MergeActionType.InsertOrUpdateAppointment
.
using DevExpress.XtraScheduler.Microsoft365Calendar;
dxOutlook365Sync1.MergeConflictResolve += DxOutlook365Sync1_MergeConflictResolve;
private void DxOutlook365Sync1_MergeConflictResolve(object sender, Outlook365CalendarMergeEventArgs e) {
DateTime appointmentLastModified = e.SchedulerAppointment.GetSchedulerChangedUTC().Value;
DateTime eventLastModified = e.OutlookEvent.LastModifiedDateTime.Value.UtcDateTime;
e.ActionType = appointmentLastModified > eventLastModified ? MergeActionType.InsertOrUpdateEvent : MergeActionType.InsertOrUpdateAppointment;
}
The DXOutlook365Sync
component raises MergeComplete after a merge operation has completed.
Customize Appointment or Event Before Synchronization
Handle the following events to customize a user appointment or event before synchronization:
- CustomizeAppointmentToEvent — Allows you to customize an event when the corresponding appointment is exported (or merged) to a Microsoft 365 calendar.
- CustomizeEventToAppointment — Allows you to customize an appointment when the corresponding event is imported (or merged) from a Microsoft 365 calendar.
The following example checks the description of appointments when they are exported (or merged) to a Microsoft 365 calendar. It adds a general description to the event before it is added to the calendar if the corresponding appointment does not have a description.
using DevExpress.XtraScheduler.Microsoft365Calendar;
private void DxOutlook365Sync1_CustomizeAppointmentToEvent(object sender, ConvertEventArgs e) {
if(e.Appointment != null && e.Appointment.Description == string.Empty)
e.Event.Body.Content = string.Format("Please describe '{0}' event.", e.Appointment.Subject);
}
Save Changes to Data Source
The DXOutlook365Sync
component requires five special fields in a data source to store identifiers of Microsoft 365 events and calendars, and the last modified date of user appointments and Microsoft 365 events.
Add the corresponding fields to a data source and define custom mappings to these fields. Appointment properties must have the following names and type:
Custom Field Name | Property Type |
---|---|
outlook365_calendar_id |
System.String |
outlook365_event_id |
System.String |
outlook365_event_ICalUId |
System.String |
outlook365_lastChangedUTC |
System.DateTime |
scheduler_lastChangedUTC |
System.DateTime |
The following example demonstrates how to create a DataTable object with special fields and define custom mappings:
DataTable source = new DataTable();
source.Columns.AddRange(new DataColumn[] {
new DataColumn("Subject", typeof(string)),
new DataColumn("Description", typeof(string)),
new DataColumn("Start", typeof(DateTime)),
new DataColumn("End", typeof(DateTime)),
// Special data fields.
new DataColumn("Outlook365CalendarId", typeof(string)),
new DataColumn("Outlook365EventId", typeof(string)),
new DataColumn("Outlook365EventUniqId", typeof(string)),
new DataColumn("Outlook365LastChangedUTC", typeof(DateTime)),
new DataColumn("SchedulerLastChangedUTC", typeof(DateTime))
});
// Binds the Scheduler Data Storage component to data and defines common mappings.
schedulerDataStorage1.Appointments.DataSource = source;
schedulerDataStorage1.Appointments.Mappings.Subject = "Subject";
schedulerDataStorage1.Appointments.Mappings.Description = "Description";
schedulerDataStorage1.Appointments.Mappings.Start = "Start";
schedulerDataStorage1.Appointments.Mappings.End = "End";
// Defines custom mappings.
schedulerDataStorage1.Appointments.CustomFieldMappings.Add(new AppointmentCustomFieldMapping("outlook365_calendar_id", "Outlook365CalendarId"));
schedulerDataStorage1.Appointments.CustomFieldMappings.Add(new AppointmentCustomFieldMapping("outlook365_event_id", "Outlook365EventId"));
schedulerDataStorage1.Appointments.CustomFieldMappings.Add(new AppointmentCustomFieldMapping("outlook365_event_ICalUId", "Outlook365EventUniqId"));
schedulerDataStorage1.Appointments.CustomFieldMappings.Add(new AppointmentCustomFieldMapping("outlook365_lastChangedUTC", "Outlook365LastChangedUTC"));
schedulerDataStorage1.Appointments.CustomFieldMappings.Add(new AppointmentCustomFieldMapping("scheduler_lastChangedUTC", "SchedulerLastChangedUTC"));
Limitations
- The
DXOutlook365Sync
component does not support synchronization of recurring appointments with a changed occurrence type.