# Binding to Business Objects

What if your scheduling data originates from somewhere other than an easily accessible database? An API that accesses a legacy system or an email based system are two examples that might fit this description. **RadScheduler** allows binding to objects of any arbitrary structure.

Binding to objects follows the same basic pattern as binding to database tables. You must assign a collection of objects to an instance of **SchedulerBindingDataSource**. You also need to define mappings so that the appointment data expected in the scheduler (Start, End, Subject, etc.) is satisfied by specific properties in the bound objects.

The code below is an example appointment. Keep in mind that the particular construction of the *CustomAppointment* class and the names of its properties are arbitrary. The mappings will decide where properties are used. Notice that the object implements the **INotifyPropertyChanged** interface. Without this interface implementation the populated appointment object data will not show up in the scheduler.

#### Custom Appointment Class

```C#
public class CustomAppointment : INotifyPropertyChanged
{
    private DateTime start = DateTime.Now;
    private DateTime end = DateTime.Now;
    private string subject = string.Empty;
    private string description = string.Empty;
    private string location = string.Empty;
    private Guid id = Guid.NewGuid();
    private List<CustomAppointment> exceptions;

    public CustomAppointment()
    {
    }

    public CustomAppointment(DateTime start, DateTime end, string subject, string description, string location)
    {
        this.start = start;
        this.end = end;
        this.subject = subject;
        this.description = description;
        this.location = location;
        List<CustomAppointment> exceptions = new List<CustomAppointment>();
    }

    public List<CustomAppointment> Exceptions
    {
        get
        {
            return this.exceptions;
        }
        set
        {
            if (this.exceptions != value)
            {
                this.exceptions = value;
                this.OnPropertyChanged("Exceptions");
            }
        }
    }

    public Guid Id
    {
        get
        {
            return this.id;
        }
        set
        {
            if (this.id != value)
            {
                this.id = value;
                this.OnPropertyChanged("Id");
            }
        }
    }

    public DateTime Start
    {
        get
        {
            return this.start;
        }
        set
        {
            if (this.start != value)
            {
                this.start = value;
                this.OnPropertyChanged("Start");
            }
        }
    }

    public DateTime End
    {
        get
        {
            return this.end;
        }
        set
        {
            if (this.end != value)
            {
                this.end = value;
                this.OnPropertyChanged("End");
            }
        }
    }

    public string Subject
    {
        get
        {
            return this.subject;
        }
        set
        {
            if (this.subject != value)
            {
                this.subject = value;
                this.OnPropertyChanged("Subject");
            }
        }
    }

    public string Description
    {
        get
        {
            return this.description;
        }
        set
        {
            if (this.description != value)
            {
                this.description = value;
                this.OnPropertyChanged("Description");
            }
        }
    }

    public string Location
    {
        get
        {
            return this.location;
        }
        set
        {
            if (this.location != value)
            {
                this.location = value;
                this.OnPropertyChanged("Location");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
```

```VB.NET
Public Class CustomAppointment
    Implements INotifyPropertyChanged

    Private _start As Date = Date.Now
    Private _end As Date = Date.Now
    Private _subject As String = String.Empty
    Private _description As String = String.Empty
    Private _location As String = String.Empty
    Private _id As Guid = Guid.NewGuid()

    Private _exceptions As List(Of CustomAppointment)

    Public Sub New()
    End Sub

    Public Sub New(ByVal start As Date, ByVal [end] As Date, ByVal subject As String, ByVal description As String, ByVal location As String)
        Me._start = start
        Me._end = [end]
        Me._subject = subject
        Me._description = description
        Me._location = location
        Dim _exceptions As New List(Of CustomAppointment)()
    End Sub

    Public Property Exceptions() As List(Of CustomAppointment)
        Get
            Return Me._exceptions
        End Get
        Set(ByVal value As List(Of CustomAppointment))
            If Me._exceptions IsNot value Then
                Me._exceptions = value
                Me.OnPropertyChanged("Exceptions")
            End If
        End Set
    End Property

    Public Property Id() As Guid
        Get
            Return Me._id
        End Get
        Set(ByVal value As Guid)
            If Me._id <> value Then
                Me._id = value
                Me.OnPropertyChanged("Id")
            End If
        End Set
    End Property

    Public Property Start() As Date
        Get
            Return Me._start
        End Get
        Set(ByVal value As Date)
            If Me._start <> value Then
                Me._start = value
                Me.OnPropertyChanged("Start")
            End If
        End Set
    End Property

    Public Property [End]() As Date
        Get
            Return Me._end
        End Get
        Set(ByVal value As Date)
            If Me._end <> value Then
                Me._end = value
                Me.OnPropertyChanged("End")
            End If
        End Set
    End Property

    Public Property Subject() As String
        Get
            Return Me._subject
        End Get
        Set(ByVal value As String)
            If Me._subject <> value Then
                Me._subject = value
                Me.OnPropertyChanged("Subject")
            End If
        End Set
    End Property

    Public Property Description() As String
        Get
            Return Me._description
        End Get
        Set(ByVal value As String)
            If Me._description <> value Then
                Me._description = value
                Me.OnPropertyChanged("Description")
            End If
        End Set
    End Property

    Public Property Location() As String
        Get
            Return Me._location
        End Get
        Set(ByVal value As String)
            If Me._location <> value Then
                Me._location = value
                Me.OnPropertyChanged("Location")
            End If
        End Set
    End Property

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    Protected Overridable Sub OnPropertyChanged(ByVal propertyName As String)
        If Me.PropertyChangedEvent IsNot Nothing Then
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End If
    End Sub
```

To use your custom object, create CustomAppointment instances and place them in a generic list before mapping and binding to the **SchedulerBindingDataSource** component.

#### Create Appointments

```C#
// create a list of CustomAppointment objects
BindingList<CustomAppointment> appointments = new BindingList<CustomAppointment>();
for (int i = 0; i < 10; i++)
{
    // add every other appointment, populate with sample data
    if ((i % 2) == 0)
    {
        int appointmentNumber = i + 1;
        CustomAppointment myAppointment =
        new CustomAppointment(
        DateTime.Now.AddHours(appointmentNumber),
        DateTime.Now.AddHours(appointmentNumber + 2),
        "Appointment " + appointmentNumber.ToString(),
        "Description for Appointment " + appointmentNumber.ToString(),
        "Conference room " + appointmentNumber.ToString());
        appointments.Add(myAppointment);
    }
}
// create and configure a scheduler binding source
SchedulerBindingDataSource dataSource = new SchedulerBindingDataSource();
// map the MyAppointment properties to the scheduler
AppointmentMappingInfo appointmentMappingInfo = new AppointmentMappingInfo();
appointmentMappingInfo.Start = "Start";
appointmentMappingInfo.End = "End";
appointmentMappingInfo.Summary = "Subject";
appointmentMappingInfo.Description = "Description";
appointmentMappingInfo.Location = "Location";
appointmentMappingInfo.UniqueId = "Id";
appointmentMappingInfo.Exceptions = "Exceptions";
dataSource.EventProvider.Mapping = appointmentMappingInfo;
// assign the generic List of CustomAppointment as the EventProvider data source
dataSource.EventProvider.DataSource = appointments;
this.radScheduler1.DataSource = dataSource;
```

```VB.NET
'create a list of CustomAppointment objects
Dim appointments As New BindingList(Of CustomAppointment)()
For i As Integer = 0 To 9
    'add every other appointment, populate with sample data
    If (i Mod 2) = 0 Then
        Dim appointmentNumber As Integer = i + 1
        Dim myAppointment As New CustomAppointment(DateTime.Now.AddHours(appointmentNumber), DateTime.Now.AddHours(appointmentNumber + 2), "Appointment " + appointmentNumber.ToString(), "Description for Appointment " + appointmentNumber.ToString(), "Conference room " + appointmentNumber.ToString())
        appointments.Add(myAppointment)
    End If
Next
'create_and_configure_a_scheduler_binding_source
Dim dataSource As New SchedulerBindingDataSource()
'map the MyAppointment properties to the scheduler
Dim appointmentMappingInfo As New AppointmentMappingInfo()
appointmentMappingInfo.Start = "Start"
appointmentMappingInfo.[End] = "End"
appointmentMappingInfo.Summary = "Subject"
appointmentMappingInfo.Description = "Description"
appointmentMappingInfo.Location = "Location"
appointmentMappingInfo.UniqueId = "Id"
appointmentMappingInfo.Exceptions = "Exceptions"
dataSource.EventProvider.Mapping = appointmentMappingInfo
'assign the generic List of CustomAppointment as the EventProvider data source
dataSource.EventProvider.DataSource = appointments
Me.radScheduler1.DataSource = dataSource
```

When you run the application, a series of CustomAppointment objects will show up in the scheduler.

> caption Figure 1: Custom Appointments

![WinForms RadScheduler Custom Appointments](https://www.telerik.com/products/winforms/documentation/assets/89421e5b18d1b629b23870a86fc97b9f/scheduler-data-binding-binding-to-business-objects001.png)

## Grouping by Resources

To use grouping by resource in this scenario, first you will need to create the business object that represents the resources:

#### Custom Resource Class

```C#
public class CustomResource : INotifyPropertyChanged
{
    private int id;
    private string name;

    public int Id
    {
        get
        {
            return this.id;
        }
        set
        {
            if (this.id != value)
            {
                this.id = value;
                this.OnPropertyChanged("Id");
            }
        }
    }

    public string Name
    {
        get
        {
            return this.name;
        }
        set
        {
            if (this.name != value)
            {
                this.name = value;
                this.OnPropertyChanged("Name");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
```

```VB.NET
Public Class CustomResource
    Implements INotifyPropertyChanged
    Private m_id As Integer
    Private m_name As String

    Public Property Id() As Integer
        Get
            Return Me.m_id
        End Get
        Set(value As Integer)
            If Me.m_id <> value Then
                Me.m_id = value
                Me.OnPropertyChanged("Id")
            End If
        End Set
    End Property

    Public Property Name() As String
        Get
            Return Me.m_name
        End Get
        Set(value As String)
            If Me.m_name <> value Then
                Me.m_name = value
                Me.OnPropertyChanged("Name")
            End If
        End Set
    End Property

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    Protected Overridable Sub OnPropertyChanged(propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub
End Class
```

Now we need to bind the **ResourceProvider** of **SchedulerBindingDataSource** to a collection of **CustomResource** objects:

#### Bind Resource Provider

```C#
BindingList<CustomResource> resources = new BindingList<CustomResource>();
for (int i = 0; i < 5; i++)
{
    CustomResource resource = new CustomResource();
    resource.Id = i;
    resource.Name = "Resource " + i;
    resources.Add(resource);
}

ResourceMappingInfo resourceMappingInfo = new ResourceMappingInfo();
resourceMappingInfo.Name = "Name";
resourceMappingInfo.Id = "Id";
dataSource.ResourceProvider.Mapping = resourceMappingInfo;
dataSource.ResourceProvider.DataSource = resources;
```

```VB.NET
Dim resources As New BindingList(Of CustomResource)()
For i As Integer = 0 To 4
    Dim resource As New CustomResource()
    resource.Id = i
    resource.Name = "Resource " & i
    resources.Add(resource)
Next

Dim resourceMappingInfo As New ResourceMappingInfo()
resourceMappingInfo.Name = "Name"
resourceMappingInfo.Id = "Id"
dataSource.ResourceProvider.Mapping = resourceMappingInfo
dataSource.ResourceProvider.DataSource = resources
```

Next we need to create the relation between appointments and resources. We can create either one-to-many relation or many-to-many relation. The following two sections cover each of these scenarios.

## One-to-many Relation

To create a one-to-many relation between appointments and resources we need to add a property of type **EventId** to the business object that represents an appointment:

#### Define One-to-many Relation

```C#
//other fields�
private EventId resourceId;

//other properties�

public EventId ResourceId
{
    get
    {
        return this.resourceId;
    }
    set
    {
        if (this.resourceId != value)
        {
            this.resourceId = value;
            this.OnPropertyChanged("ResourceId");
        }
    }
}
```

```VB.NET
'other fields�
Private _resourceId As EventId

'other properties�
Public Property ResourceId() As EventId
    Get
        Return Me._resourceId
    End Get
    Set(value As EventId)
        If Not Object.Equals(Me._resourceId, value) Then
            Me._resourceId = value
            Me.OnPropertyChanged("ResourceId")
        End If
    End Set
End Property
```

To map the new property, add the following setting to your **AppointmentMappingInfo** instance:

```C#
appointmentMappingInfo.ResourceId = "ResourceId";
```

```VB.NET
appointmentMappingInfo.ResourceId = "ResourceId"
```

> note In this scenario you should **not** set the **Resources** property of the **AppointmentMappingInfo**

#### Set Resource

```C#
CustomAppointment myAppointment =
new CustomAppointment(
DateTime.Now.AddHours(appointmentNumber),
DateTime.Now.AddHours(appointmentNumber + 2),
"Appointment " + appointmentNumber.ToString(),
"Description for Appointment " + appointmentNumber.ToString(),
"Conference room " + appointmentNumber.ToString());
appointments.Add(myAppointment);
//set the resource id
myAppointment.ResourceId = new EventId(i % 2);
```

```VB.NET
Dim myAppointment As New CustomAppointment(DateTime.Now.AddHours(appointmentNumber), DateTime.Now.AddHours(appointmentNumber + 2), "Appointment " + appointmentNumber.ToString(), "Description for Appointment " + appointmentNumber.ToString(), "Conference room " + appointmentNumber.ToString())
appointments.Add(myAppointment)
'set the resource id
```

To test this scenario, assign each appointment with a **ResourceId** and enable grouping by setting RadScheduler’s **GroupType** property:

#### Group By Resource

```C#
this.radScheduler1.GroupType = GroupType.Resource;
```

```VB.NET
Me.radScheduler1.GroupType = GroupType.Resource
```

> caption Figure 2: One-to-Many Relation

![WinForms RadScheduler One-to-Many Relation](https://www.telerik.com/products/winforms/documentation/assets/c869b8c443d49faab123c95582cbde7a/scheduler-data-binding-binding-to-business-objects002.png)

## Many-to-many Relation

This scenario can be implemented similarly to the previous one. Instead of the **ResourceId** property, we should add a **Resources** property which represents a collection of **EventId** objects:

#### Define Many-to-many Relation

```C#
//other fields�
private List<EventId> resources = new List<EventId>();

//other properties�
public List<EventId> Resources
{
    get
    {
        return this.resources;
    }
    set
    {
        if (this.resources != value)
        {
            this.resources = value;
            this.OnPropertyChanged("Resources");
        }
    }
}
```

```VB.NET
'other fields�
Private _resources As New List(Of EventId)

'other properties�
Public Property Resources() As List(Of EventId)
    Get
        Return Me._resources
    End Get
    Set(value As List(Of EventId))
        If Not Me._resources.Equals(value) Then
            Me._resources = value
            Me.OnPropertyChanged("Resources")
        End If
    End Set
End Property
```

In the **AppointmentMappingInfo** settings the **ResourceId** property should be left unset and the **Resources** property should be set with the name of the collection:

#### Set Resources

```C#
appointmentMappingInfo.Resources = "Resources";
```

```VB.NET
appointmentMappingInfo.Resources = "Resources"
```

Now we can add a resource to an appointment by adding its id in the **Resources** collection of our business objects:

```C#
myAppointment.Resources.Add(new EventId(resources[i%3].Id));
```

```VB.NET
myAppointment.Resources.Add(New EventId(resources(i Mod 3).Id))
```

> caption Figure 3: Many-to-Many Relation

![WinForms RadScheduler Many-to-Many Relation](https://www.telerik.com/products/winforms/documentation/assets/11b7cc321123fb18ebda3561b66085d1/scheduler-data-binding-binding-to-business-objects003.png)

## See Also

* [Design Time](https://www.telerik.com/products/winforms/documentation/controls/scheduler/design-time/smart-tag)
* [Views](https://www.telerik.com/products/winforms/documentation/controls/scheduler/views/overview-and-structure)
* [Scheduler Mapping](https://www.telerik.com/products/winforms/documentation/controls/scheduler/data-binding/scheduler-mapping)
* [Working with Resources](https://www.telerik.com/products/winforms/documentation/controls/scheduler/data-binding/working-with-resources)
* [setting Appointments and Resources Relations](https://www.telerik.com/products/winforms/documentation/controls/scheduler/data-binding/setting-appointment-and-resource-relations)
