# Load Data on Demand | WPF Controls | DevExpress Documentation

The [SchedulerControl](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl) can load data on demand. You can write code so that the control only fetches the items that belong to the current visible interval. Use this technique to optimize initial load time and memory consumption if the Scheduler works with a large data source.

[Run Demo: On-Demand Data Loading](dxdemo://Wpf/DXScheduling/MainDemo/OnDemandDataLoading)

[View Example](https://github.com/DevExpress-Examples/wpf-scheduler-load-data-on-demand)

To load items on demand, handle the following events:

- [Appointments](/WPF/119212/controls-and-libraries/scheduler/appointments/appointment)

    - [DataSource.FetchAppointments](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchAppointments)

- [Time Regions](/WPF/401378/controls-and-libraries/scheduler/time-regions)

    - [DataSource.FetchTimeRegions](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchTimeRegions)

Use the [FetchDataEventArgs.Result](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.Result) property to fetch data synchronously. Note that the application may freeze during the data fetch in case of a slow connection.

Use the [FetchDataEventArgs.AsyncResult](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.AsyncResult) property to fetch data asynchronously. While the Scheduler loads data, a user can navigate to other time ranges, switch between [Views](/WPF/119203/controls-and-libraries/scheduler/views), and interact with the control in other ways, except appointment changes. If the Scheduler needs time to load data, the [Wait Indicator](/WPF/114373/controls-and-libraries/windows-and-utility-controls/wait-indicator) appears. To turn off the [Wait Indicator](/WPF/114373/controls-and-libraries/windows-and-utility-controls/wait-indicator) during data load, set the [ShowWaitIndicator](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl.ShowWaitIndicator) property to `false`.

## Time Interval

The [SchedulerControl](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl) loads items based on the visible range. To load more items in advance, set your custom time interval in the [DataSource.FetchRange](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchRange) property. In the [DataSource.FetchAppointments](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchAppointments) and [DataSource.FetchTimeRegions](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchTimeRegions) event handlers, you can use the [FetchDataEventArgs.Interval](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.Interval) property to get the time range for which the Scheduler loads items.

If the [SchedulerControl.VisibleIntervals](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl.VisibleIntervals) duration is longer than [DataSource.FetchRange](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchRange), the [DataSource.FetchRange](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchRange) value is ignored. The default [DataSource.FetchRange](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchRange) value is `1 month`.

Use the [DataSource.FetchRange](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchRange) property to prevent frequent database lookups. When the [SchedulerControl.VisibleIntervals](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl.VisibleIntervals) value changes within the initially calculated [Interval](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.Interval), the [Interval](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.Interval) value is not recalculated, and the Scheduler does not load additional data.

For example, the [DataSource.FetchRange](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchRange) property has the `6 days` value. A user selects two intervals to display in the Scheduler: Day3 and Day5-Day6. The event’s [Interval](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.Interval) property is Day2-Day7. When a user selects other days within the Day2-Day7 interval, the Scheduler does not load additional data.

![The interval example](/WPF/images/scheduler-fetch-interval.png)

## Scheduler Items

Use the [FetchDataEventArgs.AsyncResult](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.AsyncResult) property to specify the list of Scheduler items to load from the data source. The [AsyncResult](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.AsyncResult) property can accept data objects or unbound Scheduler items.

### Data Objects

To pass data objects to the [AsyncResult](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.AsyncResult) property, set the [DataSource.FetchMode](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchMode) property to `Bound`. Specify the [AppointmentMappings](/WPF/DevExpress.Xpf.Scheduling.DataSource.AppointmentMappings)/[TimeRegionMappings](/WPF/DevExpress.Xpf.Scheduling.DataSource.TimeRegionMappings) property and map the [Id](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBaseMappings.Id). Refer to the following help topic for more information: [Mappings](/WPF/119493/controls-and-libraries/scheduler/data-binding/mappings).

The [FetchDataEventArgs.GetFetchExpression](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.GetFetchExpression--1) method allows you to generate an expression that obtains appointments from the data source. If the data source supports the [IQueryable](https://learn.microsoft.com/dotnet/api/system.linq.iqueryable) interface, use the following code sample to fetch data asynchronously:

- C#
- VB.NET

<section id="tabpanel_AmUoX176Lb_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">public void FetchAppointments(FetchDataEventArgs args) {
    args.AsyncResult = dbContext.AppointmentEntities
        .Where(args.GetFetchExpression&lt;AppointmentEntity&gt;())
        .ToArrayAsync&lt;object&gt;();
}
</code></pre></section>
<section id="tabpanel_AmUoX176Lb_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">Public Sub FetchAppointments(ByVal args As FetchDataEventArgs)
    Dim res = dbContext.AppointmentEntities.Where(args.GetFetchExpression(Of AppointmentEntity)())
    args.AsyncResult = QueryableExtensions.ToArrayAsync(Of Object)(res)
End Sub
</code></pre></section>

To load a [recurrent pattern](/WPF/119213/controls-and-libraries/scheduler/appointments/recurrence) for the requested [Interval](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.Interval), load all the changed and deleted occurrences for this pattern. To load recurrences accurately, use the item’s [QueryStart](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBase.QueryStart) and [QueryEnd](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBase.QueryEnd) properties.

Add two data source fields of the [System.DateTime](https://learn.microsoft.com/dotnet/api/system.datetime) type in your data source. Specify the [QueryStart](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBaseMappings.QueryStart) and [QueryEnd](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBaseMappings.QueryEnd) mappings for appointments/time regions to handle the [DataSource.FetchAppointments](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchAppointments)/[DataSource.FetchTimeRegions](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchTimeRegions) events. The Scheduler sets and updates asynchronously the values for these data properties.

Scheduler item’s [QueryStart](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBase.QueryStart) and [QueryEnd](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBase.QueryEnd) properties allow you to calculate the correct interval that is used in a SELECT query when you handle the [DataSource.FetchAppointments](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchAppointments)/[DataSource.FetchTimeRegions](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchTimeRegions) events. The use of the [TimeRegionMappings.Start](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBaseMappings.Start) and [TimeRegionMappings.End](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBaseMappings.End) properties is not recommended in this scenario because such an interval may not include time region patterns and the corresponding exceptions.

The example below illustrates how to fetch appointments from a `DbContext` source.

- C#
- VB.NET

<section id="tabpanel_AmUoX176Lb-1_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">public class SchedulingDataContext : DbContext {
    public SchedulingDataContext() : base(CreateConnection(), true) { }
    static DbConnection CreateConnection() {
        //...
    }
    public DbSet&lt;AppointmentEntity&gt; AppointmentEntities { get; set; }

    //...
}
void dataSource_FetchAppointments(object sender, DevExpress.Xpf.Scheduling.FetchDataEventArgs e) {
    e.AsyncResult = dbContext.AppointmentEntities
        .Where(x =&gt; x.QueryStart &lt;= e.Interval.End
            &amp;&amp; x.QueryEnd &gt;= e.Interval.Start)
        .ToArrayAsync&lt;object&gt;();
}
</code></pre></section>
<section id="tabpanel_AmUoX176Lb-1_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">Public Class SchedulingDataContext
    Inherits DbContext

    Public Sub New()
        MyBase.New(CreateConnection(), True)
    End Sub
    Private Shared Function CreateConnection() As DbConnection
        &#39;...
    End Function
    Public Property AppointmentEntities() As DbSet(Of AppointmentEntity)

    &#39;...
End Class
Private Sub dataSource_FetchAppointments(ByVal sender As Object, ByVal e As DevExpress.Xpf.Scheduling.FetchDataEventArgs)
    Dim res = dbContext.AppointmentEntities.Where(Function(x) x.QueryStart &lt;= e.Interval.End AndAlso x.QueryEnd &gt;= e.Interval.Start)
    args.AsyncResult = QueryableExtensions.ToArrayAsync(Of Object)(res)
End Sub
</code></pre></section>

#### Migrate Existing Projects to Load Data on Demand

You can migrate your project and use data loading on demand if your Scheduler is bound to a database. Perform the following step to implement data loading on demand:

The Scheduler calculates and updates the [QueryStart](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBase.QueryStart) and [QueryEnd](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBase.QueryEnd) values at runtime. To initialize the [QueryStart](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBase.QueryStart) and [QueryEnd](/WPF/DevExpress.Xpf.Scheduling.SchedulerItemBase.QueryEnd) values in your database, load all database records to the Scheduler and then save changes to the data source:

- C#
- VB.NET

<section id="tabpanel_AmUoX176Lb-2_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">dbContext.AppointmentEntities.Load();
scheduler.DataSource.AppointmentsSource = dbContext.AppointmentEntities.Local;
dbContext.SaveChanges();
</code></pre></section>
<section id="tabpanel_AmUoX176Lb-2_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">dbContext.AppointmentEntities.Load()
scheduler.DataSource.AppointmentsSource = dbContext.AppointmentEntities.Local
dbContext.SaveChanges()
</code></pre></section>

### Unbound Items

If you do not use [DataSource.AppointmentMappings](/WPF/DevExpress.Xpf.Scheduling.DataSource.AppointmentMappings) and [DataSource.TimeRegionMappings](/WPF/DevExpress.Xpf.Scheduling.DataSource.TimeRegionMappings) to bind the Scheduler to a data source, load Scheduler items ([AppointmentItem](/WPF/DevExpress.Xpf.Scheduling.AppointmentItem) and [TimeRegionItem](/WPF/DevExpress.Xpf.Scheduling.TimeRegionItem) instances) instead of data items. To pass Scheduler items to the [Result](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.Result) property, set the [DataSource.FetchMode](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchMode) property to `Unbound`.

- C#
- VB.NET

<section id="tabpanel_AmUoX176Lb-3_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">void FetchAppointments(object sender, FetchDataEventArgs e) {
    e.AsyncResult = MyCalendarService
        .GetEvents(e.Interval.Start, e.Interval.End)
        .ContinueWith(t =&gt; t.Result.Select(Convert).ToArray&lt;object&gt;());
}
AppointmentItem Convert(Event x) {
    var appt = new AppointmentItem() { Id = x.Id };
    //..
    return appt;
}
</code></pre></section>
<section id="tabpanel_AmUoX176Lb-3_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">Class SurroundingClass
    Private Sub FetchAppointments(ByVal sender As Object, ByVal e As FetchDataEventArgs)
        e.AsyncResult = MyCalendarService.GetEvents(e.Interval.Start, e.Interval.[End]).ContinueWith(Function(t) t.Result.[Select](AddressOf Convert).ToArray(Of Object)())
    End Sub

    Private Function Convert(ByVal x As [Event]) As AppointmentItem
        Dim appt = New AppointmentItem() With {
            .Id = x.Id
        }
        Return appt
    End Function
End Class
</code></pre></section>

## Save Changes

If you handle the [DataSource.FetchAppointments](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchAppointments) event, you need to handle the following events to save the changes to the data source:

- [SchedulerControl.AppointmentAdded](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl.AppointmentAdded)
- [SchedulerControl.AppointmentEdited](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl.AppointmentEdited)
- [SchedulerControl.AppointmentRemoved](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl.AppointmentRemoved)
- [SchedulerControl.AppointmentRestored](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl.AppointmentRestored)

You can use the [AppointmentCRUDEventArgs](/WPF/DevExpress.Xpf.Scheduling.AppointmentCRUDEventArgs) class to implement a single event handler for all four events:

- XAML

<section id="tabpanel_AmUoX176Lb-4_tabid-xaml" role="tabpanel" data-tab="tabid-xaml">
<pre><code class="lang-xaml">&lt;dxsch:SchedulerControl
    AppointmentAdded=&quot;ProcessChanges&quot;
    AppointmentEdited=&quot;ProcessChanges&quot;
    AppointmentRemoved=&quot;ProcessChanges&quot;
    AppointmentRestored=&quot;ProcessChanges&quot;/&gt;    
</code></pre></section>

- C#
- VB.NET

<section id="tabpanel_AmUoX176Lb-5_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">void ProcessChanges(object sender, AppointmentCRUDEventArgs e) {
    db.Appointments.AddRange(e.AddToSource.Select(x =&gt; (Appointment)x.SourceObject));
    db.Appointments.RemoveRange(e.DeleteFromSource.Select(x =&gt; (Appointment)x.SourceObject));
    db.SaveChanges();
} 
</code></pre></section>
<section id="tabpanel_AmUoX176Lb-5_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">Private Sub ProcessChanges(ByVal sender As Object, ByVal e As AppointmentCRUDEventArgs)
    db.Appointments.AddRange(e.AddToSource.Select(Function(x) CType(x.SourceObject, Appointment)))
    db.Appointments.RemoveRange(e.DeleteFromSource.Select(Function(x) CType(x.SourceObject, Appointment)))
    db.SaveChanges()
End Sub
</code></pre></section>

## One DbContext per Request

If you use the *One DbContext per request* approach, initialize the DbContext in the [DataSource.FetchAppointments](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchAppointments) event handler:

- C#
- VB.NET

<section id="tabpanel_AmUoX176Lb-6_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">void FetchAppointments(object sender, FetchDataEventArgs e) {
    using(var db = new SchedulingContext()) {
        e.AsyncResult = db.Appointments
            .Where(e.GetFetchExpression&lt;Appointment&gt;())
            .ToArrayAsync&lt;object&gt;();
    }
}
</code></pre></section>
<section id="tabpanel_AmUoX176Lb-6_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">Public Sub FetchAppointments(ByVal args As FetchDataEventArgs)
    Using dbContext = New SchedulingContext()
        Dim res = dbContext.AppointmentEntities.Where(args.GetFetchExpression(Of AppointmentEntity)())
        args.AsyncResult = QueryableExtensions.ToArrayAsync(Of Object)(res)
    End Using
End Sub
</code></pre></section>

In this scenario, use the event’s [UpdateInSource](/WPF/DevExpress.Xpf.Scheduling.AppointmentCRUDEventArgs.UpdateInSource) property to save the changes to the existing appointments. You also need to search appointments by their `Id` to update or delete them:

- C#
- VB.NET

<section id="tabpanel_AmUoX176Lb-7_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">void ProcessChanges(object sender, AppointmentCRUDEventArgs e) {
    using(var db = new SchedulingContext()) {
        db.Appointments.AddRange(e.AddToSource.Select(x =&gt; (Appointment)x.SourceObject));
        foreach(var appt in e.UpdateInSource.Select(x =&gt; (Appointment)x.SourceObject))
            AppointmentHelper.CopyProperties(appt, db.Appointments.Find(appt.Id));
        foreach(var appt in e.DeleteFromSource.Select(x =&gt; (Appointment)x.SourceObject))
            db.Appointments.Remove(db.Appointments.Find(appt.Id));
        db.SaveChanges();
    }
}
public class AppointmentHelper {
    public static void CopyProperties(Appointment source, Appointment target) {
        target.AllDay = source.AllDay;
        target.AppointmentType = source.AppointmentType;
        target.Description = source.Description;
        target.End = source.End;
        target.Label = source.Label;
        target.Location = source.Location;
        target.QueryEnd = source.QueryEnd;
        target.QueryStart = source.QueryStart;
        target.RecurrenceInfo = source.RecurrenceInfo;
        target.ReminderInfo = source.ReminderInfo;
        target.ResourceId = source.ResourceId;
        target.Start = source.Start;
        target.Status = source.Status;
        target.Subject = source.Subject;
    }
}
</code></pre></section>
<section id="tabpanel_AmUoX176Lb-7_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">Private Sub ProcessChanges(ByVal sender As Object, ByVal e As AppointmentCRUDEventArgs)
    Using db = New SchedulingContext()
        db.Appointments.AddRange(e.AddToSource.Select(Function(x) CType(x.SourceObject, Appointment)))
        For Each appt In e.UpdateInSource.Select(Function(x) CType(x.SourceObject, Appointment))
            AppointmentHelper.CopyProperties(appt, db.Appointments.Find(appt.Id))
        Next appt
        For Each appt In e.DeleteFromSource.Select(Function(x) CType(x.SourceObject, Appointment))
            db.Appointments.Remove(db.Appointments.Find(appt.Id))
        Next appt
        db.SaveChanges()
    End Using
End Sub
Public Class AppointmentHelper
    Public Shared Sub CopyProperties(ByVal source As Appointment, ByVal target As Appointment)
        target.AllDay = source.AllDay
        target.AppointmentType = source.AppointmentType
        target.Description = source.Description
        target.End = source.End
        target.Label = source.Label
        target.Location = source.Location
        target.QueryEnd = source.QueryEnd
        target.QueryStart = source.QueryStart
        target.RecurrenceInfo = source.RecurrenceInfo
        target.ReminderInfo = source.ReminderInfo
        target.ResourceId = source.ResourceId
        target.Start = source.Start
        target.Status = source.Status
        target.Subject = source.Subject
    End Sub
End Class
</code></pre></section>

## Reload and Refresh Data

Use the [ReloadAppointments](/WPF/DevExpress.Xpf.Scheduling.DataSource.ReloadAppointments%28System.Object--%29)/[ReloadTimeRegions](/WPF/DevExpress.Xpf.Scheduling.DataSource.ReloadTimeRegions%28System.Object--%29) methods to reload specified appointments and time regions. Use the event’s [FetchDataEventArgs.Ids](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.Ids) property to obtain the identifiers of the items that need to be updated in the Scheduler. If the fetch event has not been fired by the [ReloadAppointments](/WPF/DevExpress.Xpf.Scheduling.DataSource.ReloadAppointments%28System.Object--%29)/[ReloadTimeRegions](/WPF/DevExpress.Xpf.Scheduling.DataSource.ReloadTimeRegions%28System.Object--%29) methods, the [FetchDataEventArgs.Ids](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.Ids) property returns `null`.

The code snippet below illustrates the [FetchAppointments](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchAppointments) event implementation.

- C#
- VB.NET

<section id="tabpanel_AmUoX176Lb-8_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code class="lang-csharp">scheduler.ReloadAppointment(new[] { id1, id2 });
//...
public void FetchAppointments(FetchDataEventArgs args) {
    if(args.Ids == null)
    // event has been fired by the scheduler&#39;s initialization or navigation
        args.AsyncResult = dbContext.AppointmentEntities
            .Where(x =&gt; x.QueryStart &lt;= args.Interval.End &amp;&amp; x.QueryEnd &gt;= args.Interval.Start)
            .ToArrayAsync&lt;object&gt;();
    else {
    // event has been fired by the ReloadAppointments method
        var ids = args.Ids.OfType&lt;int&gt;().ToArray();
        args.AsyncResult = dbContext.AppointmentEntities
            .Where((x) =&gt; ids.Contains(x.Id))
            .ToArrayAsync&lt;object&gt;();
    }
}
</code></pre></section>
<section id="tabpanel_AmUoX176Lb-8_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code class="lang-vb">scheduler.ReloadAppointment( { id1, id2 })
&#39;...
Public Sub FetchAppointments(ByVal args As FetchDataEventArgs)
    If args.Ids Is Nothing Then
    &#39; event has been fired by the scheduler&#39;s initialization or navigation
        args.AsyncResult = dbContext.AppointmentEntities
        .Where(Function(x) x.QueryStart &lt;= args.Interval.End AndAlso x.QueryEnd &gt;= args.Interval.Start)
        .ToArrayAsync(Of Object)()
    Else
    &#39; event has been fired by the ReloadAppointments method
        Dim ids = args.Ids.OfType(Of Integer)().ToArray()
        Dim res = dbContext.AppointmentEntities.Where(args.GetFetchExpression(Of AppointmentEntity)())
        args.AsyncResult = QueryableExtensions.ToArrayAsync(Of Object)(res)
    End If
End Sub
</code></pre></section>

The [RefreshData()](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl.RefreshData) method clears the cached appointments/time regions and fires the [DataSource.FetchAppointments](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchAppointments) and [DataSource.FetchTimeRegions](/WPF/DevExpress.Xpf.Scheduling.DataSource.FetchTimeRegions) events. You can use the [CancellationToken](/WPF/DevExpress.Xpf.Scheduling.FetchDataEventArgs.CancellationToken) property to cancel the data load. 

To set up retries after an exception is thrown, you can use the [AutoRetryFetchTimeOut](/WPF/DevExpress.Xpf.Scheduling.DataSource.AutoRetryFetchTimeOut) and [AutoRetryFetchMaxCount](/WPF/DevExpress.Xpf.Scheduling.DataSource.AutoRetryFetchMaxCount) properties. When the [AutoRetryFetchTimeOut](/WPF/DevExpress.Xpf.Scheduling.DataSource.AutoRetryFetchTimeOut) or [AutoRetryFetchMaxCount](/WPF/DevExpress.Xpf.Scheduling.DataSource.AutoRetryFetchMaxCount) values are exceeded, the **Retry** window appears.

## Limitations

- [List view](/WPF/400421/controls-and-libraries/scheduler/views/list-view) always loads all appointments.
- The [CustomAllowAppointmentConflicts](/WPF/DevExpress.Xpf.Scheduling.SchedulerControl.CustomAllowAppointmentConflicts) event only processes loaded appointments.
- Navigation buttons are shown only for loaded appointments.
- Dates with appointments are not highlighted in the [Date Navigator](/WPF/401550/controls-and-libraries/scheduler/visual-elements/date-navigator).

## Example

[View Example](https://github.com/DevExpress-Examples/wpf-scheduler-load-data-on-demand)

This example consists of three parts.

- *Shared*. The project includes the data and the view that are the same for both examples.
- *CommonDbContext*. The project uses a single DbContext for the application and has its own `SchedulingViewModel`.
- *DbContextPerRequest*. This project follows the *One DbContext per request* approach and has its own `SchedulingViewModel`.