New to Telerik UI for WinForms? Download free 30-day trial

Data Binding Walkthrough

This walkthrough will cover creating and binding RadScheduler to a data source in a step-by-step manner.

Another example of binding RadScheduler is available in our Telerik UI for WinForms Step-by-step Tutorial

The Database

RadScheduler has a very flexible binding system which can cover various binding scenarios. Most of them are covered in the next articles. Here we will cover the scenario with binding to a database in which appointments and resources are in a many-to-many relation. A sample database ships with our products and can be found under [Your installation directory]\Examples\QuickStart\DataSources\SchedulerData.mdb. By default the installation directory is C:\Program Files\Telerik\UI for WinForms\Version\

The following screen shot demonstrates the schema of the database.

WinForms RadScheduler Database Schema

Binding the Scheduler

Let’s assume you have added a RadScheduler to your form and you want to bind it to a data source. To do so you must first create and set up a SchedulerBindingDataSource instance. SchedulerBindingDataSource is a component and is available in your toolbox. To setup a SchedulerBindingDataSource, follow these steps:

  1. Add a SchedulerBindingDataSource from the Toolbox to the form.

  2. In the Properties window, open the EventProvider property. Drop down the DataSource sub-property list and select Add Project DataSource... This step will display the Data Source Configuration Wizard dialog.

WinForms RadScheduler Form Designer

  1. Complete this wizard by choosing Access Database File connection and selecting the sample database located under the \Examples\DataSources directory. This will create a DataSet component and add it to the component tray below the form designer. WinForms RadScheduler Relation Dialog

  2. Click the "SchedulerDataDataSet" Smart Tag and select Edit in Dataset Designer. Add a relation between the Appointments and AppointmentsResources tables and name it "Appointments_AppointmentsResources". Make the "Key Columns" entry be "ID" from the Appointments table and set "Foreign Key Columns" from the AppointmentsResources table to "AppointmentID".WinForms RadScheduler SchedulerDataDataSet

  3. When you create a dataset from the MS Access database, several properties of the auto number fields are wrongly set. Please, set these as in the right (correct) version below:WinForms RadScheduler MS Access database

  4. Build the project. This step will create several useful adapter components that we will use later to fill the dataset.WinForms RadScheduler Adapter Components

Mapping the Properties

In order to map the fields of your data source to the correct properties of scheduler’s objects, you need to setup two mapping info instances: one of type AppointmentMappingInfo and one of type ResourceMappingInfo. You can do this either through code or in the Visual Studio designer.

To setup appointment mapping at design time, click the Edit Appointment Mapping button in the smart tag menu of your SchedulerBindingDataSource instance. To edit the resource mapping, click the Edit Resource Mapping button.

WinForms RadScheduler Mapping

When you do so, a dialog will appear letting you choose the field of the data source which should be mapped to the corresponding appointment/resource property.

The data source fields should be set prior editing the mapping in order to get automatically populated with data source fields drop downs.

The Resources property of the AppointmentMappingInfo should be set with the name of the relationthat connects the Appointments and the AppointmentsResources tables. The ResourceId property shouldbe set with the name of the column in the AppointmentsResources table that holds the id of the resource.

Programatically Mapping

In order to programatically map the fields of your data source to the correct properties of scheduler’s objects, you need to setup two mapping info instances: one of type AppointmentMappingInfo and one of type ResourceMappingInfo and assign them to the SchedulerBindingDataSource instance as it is demonstrated below.

AppointmentMappingInfo appointmentMappingInfo = new AppointmentMappingInfo();
appointmentMappingInfo.BackgroundId = "BackgroundID";
appointmentMappingInfo.Description = "Description";
appointmentMappingInfo.End = "End";
appointmentMappingInfo.Location = "Location";
appointmentMappingInfo.MasterEventId = "ParentID";
appointmentMappingInfo.RecurrenceRule = "RecurrenceRule";
appointmentMappingInfo.ResourceId = "ResourceID";
appointmentMappingInfo.Resources = "Appointments_AppointmentsResources";
appointmentMappingInfo.Start = "Start";
appointmentMappingInfo.StatusId = "StatusID";
appointmentMappingInfo.Summary = "Summary";
schedulerBindingDataSource1.EventProvider.Mapping = appointmentMappingInfo;
ResourceMappingInfo resourceMappingInfo = new ResourceMappingInfo();
resourceMappingInfo.Id = "ID";
resourceMappingInfo.Name = "ResourceName";
this.schedulerBindingDataSource1.ResourceProvider.Mapping = resourceMappingInfo;

Dim appointmentMappingInfo As New AppointmentMappingInfo()
appointmentMappingInfo.BackgroundId = "BackgroundID"
appointmentMappingInfo.Description = "Description"
appointmentMappingInfo.[End] = "End"
appointmentMappingInfo.Location = "Location"
appointmentMappingInfo.MasterEventId = "ParentID"
appointmentMappingInfo.RecurrenceRule = "RecurrenceRule"
appointmentMappingInfo.ResourceId = "ResourceID"
appointmentMappingInfo.Resources = "Appointments_AppointmentsResources"
appointmentMappingInfo.Start = "Start"
appointmentMappingInfo.StatusId = "StatusID"
appointmentMappingInfo.Summary = "Summary"
SchedulerBindingDataSource1.EventProvider.Mapping = appointmentMappingInfo
Dim resourceMappingInfo As New ResourceMappingInfo()
resourceMappingInfo.Id = "ID"
resourceMappingInfo.Name = "ResourceName"
Me.SchedulerBindingDataSource1.ResourceProvider.Mapping = resourceMappingInfo

As of R1 2021 the EditAppointmentDialog provides UI for selecting multiple resources per appointment. In certain cases (e.g. unbound mode), the Resource RadDropDownList is replaced with a RadCheckedDropDownList. Otherwise, the default drop down with single selection for resources is shown. To enable the multiple resources selection in bound mode, it is necessary to specify the AppointmentMappingInfo. Resources property. The Resources property should be set to the name of the relation that connects the Appointments and the AppointmentsResources tables.

EditAppointmentDialog with multiple resources

WinForms RadScheduler Edit Dialog Multiple Resource

Retrieving the Data

To retrieve the data, first we need to fill the data set:

this.resourcesTableAdapter.Fill(this.schedulerDataDataSet.Resources);
this.appointmentsResourcesTableAdapter.Fill(this.schedulerDataDataSet.AppointmentsResources);
this.appointmentsTableAdapter.Fill(this.schedulerDataDataSet.Appointments);

Me.ResourcesTableAdapter.Fill(Me.SchedulerDataDataSet.Resources)
Me.AppointmentsResourcesTableAdapter.Fill(Me.SchedulerDataDataSet.AppointmentsResources)
Me.AppointmentsTableAdapter.Fill(Me.SchedulerDataDataSet.Appointments)

You should fill the tables in the exact same order if you have already set the DataSource property of RadScheduler. Alternatively, you can just call the DataBind method of RadScheduler after you fill the tables.

Now we need to assign the Appointments and Resources tables from the data set to our SchedulerBindingDataSource (the following can also be set at design time through the Smart Tag of your SchedulerBindingDataSource instance as you can see on the previous image):

schedulerBindingDataSource1.ResourceProvider.DataSource = schedulerDataDataSet.Resources;
schedulerBindingDataSource1.EventProvider.DataSource = schedulerDataDataSet.Appointments;

SchedulerBindingDataSource1.ResourceProvider.DataSource = SchedulerDataDataSet.Resources
SchedulerBindingDataSource1.EventProvider.DataSource = SchedulerDataDataSet.Appointments

Finally, we assign our SchedulerBindingDataSource instance to RadScheduler as its DataSource. This can be achieved either through the Smart Tag of RadScheduler or via code:

WinForms RadScheduler SchedulerBindingDataSource

radScheduler1.DataSource = schedulerBindingDataSource1;

RadScheduler1.DataSource = SchedulerBindingDataSource1

If the above steps are not performed in the same order, RadScheduler might not display the appointments. In this case you can try calling the DataBind method of RadScheduler or the Rebind method of SchedulerBindingDataSource.

Updating the Database

Add the following code to the Click event handler for an "Update" button, which will update the data source. (for more information on saving data, see MSDN:How to: Update Data by Using a TableAdapter).Note that we need to update the added, modified and deleted records in a certain order because of the relations between our tables.We also need to use the two dictionaries to keep track of the automatically generated IDs before and after calling Update. This is due to a synchronization problem between the database and the data set, where the data adapter could not update correctly the ID of the added row. This happens because the IDs generated locally might differ from the IDs generated from the database(for example when multiple users work simultaneously) and we use this IDs to store the relation between appointments and resources. (Here is an MSDN article which describes this limitation:Retrieving Identity or Autonumber Values)

private void btnUpdate_Click(object sender, EventArgs e)
{
    appointmentsResourcesTableAdapter.Adapter.AcceptChangesDuringUpdate = false;
    SchedulerDataDataSet.AppointmentsResourcesDataTable deletedRelationRecords =
                    this.schedulerDataDataSet.AppointmentsResources.GetChanges(DataRowState.Deleted)
                    as SchedulerDataDataSet.AppointmentsResourcesDataTable;
    SchedulerDataDataSet.AppointmentsResourcesDataTable newRelationRecords =
                    this.schedulerDataDataSet.AppointmentsResources.GetChanges(DataRowState.Added)
                    as SchedulerDataDataSet.AppointmentsResourcesDataTable;
    SchedulerDataDataSet.AppointmentsResourcesDataTable modifiedRelationRecords =
                    this.schedulerDataDataSet.AppointmentsResources.GetChanges(DataRowState.Modified)
                    as SchedulerDataDataSet.AppointmentsResourcesDataTable;
    SchedulerDataDataSet.AppointmentsDataTable newAppointmentRecords =
        this.schedulerDataDataSet.Appointments.GetChanges(DataRowState.Added) as SchedulerDataDataSet.AppointmentsDataTable;
    SchedulerDataDataSet.AppointmentsDataTable deletedAppointmentRecords =
        this.schedulerDataDataSet.Appointments.GetChanges(DataRowState.Deleted) as SchedulerDataDataSet.AppointmentsDataTable;
    SchedulerDataDataSet.AppointmentsDataTable modifiedAppointmentRecords =
        this.schedulerDataDataSet.Appointments.GetChanges(DataRowState.Modified) as SchedulerDataDataSet.AppointmentsDataTable;
    try
    {
        if (newAppointmentRecords != null)
        {
            Dictionary<int, int> newAppointmentIds = new Dictionary<int, int>();
            Dictionary<object, int> oldAppointmentIds = new Dictionary<object, int>();
            for (int i = 0; i < newAppointmentRecords.Count; i++)
            {
                oldAppointmentIds.Add(newAppointmentRecords[i], newAppointmentRecords[i].ID);
            }
            appointmentsTableAdapter.Update(newAppointmentRecords);
            for (int i = 0; i < newAppointmentRecords.Count; i++)
            {
                newAppointmentIds.Add(oldAppointmentIds[newAppointmentRecords[i]], newAppointmentRecords[i].ID);
            }
            if (newRelationRecords!=null)
            {
                for (int i = 0; i < newRelationRecords.Count; i++)
                {
                newRelationRecords[i].AppointmentID = newAppointmentIds[newRelationRecords[i].AppointmentID];
                }
            }
        }
        if (deletedRelationRecords != null)
        {
            appointmentsResourcesTableAdapter.Update(deletedRelationRecords);
        }
        if (deletedAppointmentRecords != null)
        {
            appointmentsTableAdapter.Update(deletedAppointmentRecords);
        }
        if (modifiedAppointmentRecords != null)
        {
            appointmentsTableAdapter.Update(modifiedAppointmentRecords);
        }
        if (newRelationRecords != null)
        {
            appointmentsResourcesTableAdapter.Update(newRelationRecords);
        }
        if (modifiedRelationRecords != null)
        {
            appointmentsResourcesTableAdapter.Update(modifiedRelationRecords);
        }
        this.schedulerDataDataSet.AcceptChanges();
    }
    catch (Exception ex)
    {
        MessageBox.Show(string.Format("An error occurred during the update process:\n{0}", ex.Message));
    }
    finally
    {
        if (deletedRelationRecords != null)
        {
            deletedRelationRecords.Dispose();
        }
        if (newRelationRecords != null)
        {
            newRelationRecords.Dispose();
        }
        if (modifiedRelationRecords != null)
        {
            modifiedRelationRecords.Dispose();
        }
    }
    lblStatus.Text = "Updated scheduler at " + DateTime.Now.ToString();
}

Private Sub btnUpdate_Click(ByVal sender As Object, ByVal e As EventArgs)
    AppointmentsResourcesTableAdapter.Adapter.AcceptChangesDuringUpdate = False
    Dim deletedRelationRecords As SchedulerDataDataSet.AppointmentsResourcesDataTable = TryCast(Me.SchedulerDataDataSet.AppointmentsResources.GetChanges(DataRowState.Deleted), SchedulerDataDataSet.AppointmentsResourcesDataTable)
    Dim newRelationRecords As SchedulerDataDataSet.AppointmentsResourcesDataTable = TryCast(Me.SchedulerDataDataSet.AppointmentsResources.GetChanges(DataRowState.Added), SchedulerDataDataSet.AppointmentsResourcesDataTable)
    Dim modifiedRelationRecords As SchedulerDataDataSet.AppointmentsResourcesDataTable = TryCast(Me.SchedulerDataDataSet.AppointmentsResources.GetChanges(DataRowState.Modified), SchedulerDataDataSet.AppointmentsResourcesDataTable)
    Dim newAppointmentRecords As SchedulerDataDataSet.AppointmentsDataTable = TryCast(Me.SchedulerDataDataSet.Appointments.GetChanges(DataRowState.Added), SchedulerDataDataSet.AppointmentsDataTable)
    Dim deletedAppointmentRecords As SchedulerDataDataSet.AppointmentsDataTable = TryCast(Me.SchedulerDataDataSet.Appointments.GetChanges(DataRowState.Deleted), SchedulerDataDataSet.AppointmentsDataTable)
    Dim modifiedAppointmentRecords As SchedulerDataDataSet.AppointmentsDataTable = TryCast(Me.SchedulerDataDataSet.Appointments.GetChanges(DataRowState.Modified), SchedulerDataDataSet.AppointmentsDataTable)
    Try
        If newAppointmentRecords IsNot Nothing Then
            Dim newAppointmentIds As New Dictionary(Of Integer, Integer)()
            Dim oldAppointmentIds As New Dictionary(Of Object, Integer)()
            For i As Integer = 0 To newAppointmentRecords.Count - 1
                oldAppointmentIds.Add(newAppointmentRecords(i), newAppointmentRecords(i).ID)
            Next
            AppointmentsTableAdapter.Update(newAppointmentRecords)
            For i As Integer = 0 To newAppointmentRecords.Count - 1
                newAppointmentIds.Add(oldAppointmentIds(newAppointmentRecords(i)), newAppointmentRecords(i).ID)
            Next
            If newRelationRecords IsNot Nothing Then
                For i As Integer = 0 To newRelationRecords.Count - 1
                    newRelationRecords(i).AppointmentID = newAppointmentIds(newRelationRecords(i).AppointmentID)
                Next
            End If
        End If
        If deletedRelationRecords IsNot Nothing Then
            AppointmentsResourcesTableAdapter.Update(deletedRelationRecords)
        End If
        If deletedAppointmentRecords IsNot Nothing Then
            AppointmentsTableAdapter.Update(deletedAppointmentRecords)
        End If
        If modifiedAppointmentRecords IsNot Nothing Then
            AppointmentsTableAdapter.Update(modifiedAppointmentRecords)
        End If
        If newRelationRecords IsNot Nothing Then
            AppointmentsResourcesTableAdapter.Update(newRelationRecords)
        End If
        If modifiedRelationRecords IsNot Nothing Then
            AppointmentsResourcesTableAdapter.Update(modifiedRelationRecords)
        End If
        Me.SchedulerDataDataSet.AcceptChanges()
    Catch ex As Exception
        MessageBox.Show(String.Format("An error occurred during the update process:" & vbLf & "{0}", ex.Message))
    Finally
        If deletedRelationRecords IsNot Nothing Then
            deletedRelationRecords.Dispose()
        End If
        If newRelationRecords IsNot Nothing Then
            newRelationRecords.Dispose()
        End If
        If modifiedRelationRecords IsNot Nothing Then
            modifiedRelationRecords.Dispose()
        End If
    End Try
    lblStatus.Text = "Updated scheduler at " + DateTime.Now.ToString()
End Sub

Figure 1: Data Bound RadScheduler

WinForms RadScheduler Data Bound RadScheduler

See Also

In this article