Skip to main content
All docs
V24.1

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

public class DXOutlook365Sync :
    Component

Remarks

Examples

The following GitHub examples demonstrate how to synchronize user appointments with Microsoft 365 calendars (import, export, merge):

Get Started

Install the following dependency libraries (NuGet packages):

  1. Azure.Identity 1.11.0+
  2. HtmlAgilityPack 1.11.46
  3. Microsoft.Graph 4.49.0

Then add the DXOutlook365Sync component to the project.

WinForms 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 DXOutlook365Sync to the Windows Forms Project

WPF Project

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.

Sign In - WinForms Synchronization with Microsoft 365 Calendars

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:

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:

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

Inheritance

See Also