MindFusion.Scheduling for WebForms gives you the possibility of extending the available Item and Resource classes to include your own business logic in a Schedule.
Custom Items
In order to integrate your custom class into the calendar API, you must do the following:
1. Derive from either Item or Appointment and provide a parameterless constructor to your custom class and extend it to your liking.
For example:
C#
Copy Code
|
---|
using MindFusion.Scheduling;
public class MyCustomItem: Appointment { public MyCustomItem() { }
public int RecordedValue { get { return recordedValue; } set { recordedValue = value; } }
private int recordedValue; } |
Visual Basic
Copy Code
|
---|
Imports MindFusion.Scheduling
Public Class MyCustomItem Inherits Appointment
Public Sub New() End Sub
Public Property RecordedValue() As Integer Get Return recValue End Get Set(ByVal value As Integer) recValue = value End Set End Property
Private recValue As Integer End Class |
2. Enable ViewState on your custom item.
In order to save your custom properties in the ViewState of your custom item you should override the SaveViewState and LoadViewState methods of the Item class.
C#
Copy Code
|
---|
public override object SaveViewState() { ViewState["_recordedValue"] = RecordedValue; return base.SaveViewState(); }
public override void LoadViewState(object state) { base.LoadViewState(state); if (ViewState["_recordedValue"] != null) { RecordedValue = (int)ViewState["_recordedValue"]; } } |
Visual Basic
Copy Code
|
---|
Public Overrides Function SaveViewState() As Object ViewState("_recordedValue") = RecordedValue Return MyBase.SaveViewState() End Function
Public Overrides Sub LoadViewState(state As Object) MyBase.LoadViewState(state) If ViewState("_recordedValue") IsNot Nothing Then RecordedValue = CInt(ViewState("_recordedValue")) End If End Sub |
3. Serialization
Serialization of custom items requires additional efforts. Attempts to save a schedule containing items of type MyCustomItem will result in an InvalidOperationException exception. In order to support serialization, we have to register MyCustomItem with the schedule. For this purpose, add the following line of code somewhere in the page's Load event handler:
C#
Copy Code
|
---|
Schedule.RegisterItemClass(typeof(MyCustomItem), "myitem", 1); |
Visual Basic
Copy Code
|
---|
Schedule.RegisterItemClass(GetType(MyCustomItem), "myitem", 1) |
Now the exception won't be thrown, but we still need to override the SaveTo and LoadFrom methods of the Appointment class in order to serialize the custom property RecordedValue. The code below illustrates how this is done for the SaveTo and LoadFrom overloads that serialize item's contents in binary streams.
C#
Copy Code
|
---|
public override void SaveTo(System.IO.BinaryWriter writer, BinarySerializationContext context) { base.SaveTo(writer, context); context.WriteInt(writer, recordedValue); }
public override void LoadFrom(System.IO.BinaryReader reader, BinarySerializationContext context) { base.LoadFrom(reader, context); recordedValue = context.ReadInt(reader); } |
Visual Basic
Copy Code
|
---|
Public Overloads Overrides Sub SaveTo(ByVal writer As System.IO.BinaryWriter, ByVal context As BinarySerializationContext) MyBase.SaveTo(writer, context) context.WriteInt(writer, recValue) End Sub Public Overloads Overrides Sub LoadFrom(ByVal reader As System.IO.BinaryReader, ByVal context As SerializationContext) MyBase.LoadFrom(reader, context) recValue = context.ReadInt(reader) End Sub |
A code that implements serialization of items in XML format would look similar to the above, but it will override the other SaveTo and LoadFrom method overloads.
4. Recurrences
Recurrence of items from a custom class is not handled wholly automatically. Let's take a closer look at how recurrence works in MindFusion.Scheduling for WebForms. When a recurrence pattern is associated with an existing item, the item is said to become the master of the recurrence. Every time the occurrences of a master item must be displayed in a given time range, they are generated by instantiating new objects of the same type as that of the master. This is necessary in order to support infinite recurrences, where the generation of all recurrence instances is not possible. When the occurrences are generated, their properties are copied from the master item. This is done automatically for the built-in item properties, but not for those added by a derived item class. In order to copy the custom properties from the master item to a particular occurrence, you need to override the CopyOccurrence method. The following code sample shows how to do this.
C#
Copy Code
|
---|
protected override void CopyOccurrence(Item master) { base.CopyOccurrence(master); recordedValue = (master as MyCustomItem).RecordedValue; } |
Visual Basic
Copy Code
|
---|
Protected Overloads Overrides Sub CopyOccurrence(ByVal master As Item) MyBase.CopyOccurrence(master) recValue = CType(master, MyCustomItem).RecordedValue End Sub |
In addition, it is recommended to mark an item from a recurrent series as an exception when the value of a custom property changes. Otherwise, the change will be lost the next time the instance is generated.
C#
Copy Code
|
---|
// ... public int RecordedValue { get { return recordedValue; } set { recordedValue = value;
if (Recurrence != null) Recurrence.MarkException(this, false); } } // ... |
Visual Basic
Copy Code
|
---|
' ... Public Property RecordedValue() As Integer Get Return recordedValue End Get Set(ByVal value As Integer) recValue = value
If Not Recurrence Is Nothing Then Recurrence.MarkException(Me, False) End If End Set End Property ' ... |
5. Accessing your custom properties from the client
In order to transfer the custom properties of your items to the client side, you must supply a JavaScriptConverter that will handle the serialization to a JSON string, that will be used by the Calendar to recreate the items, created on the server. The easiest way to do that is to derive from ItemConverter, override the SupportedTypes property and include the serialization logic in the Serialize override. For example:
C#
Copy Code
|
---|
using MindFusion.Scheduling.WebForms;
class MyCustomItemConverter : ItemConverter { public MyCustomItemConverter(Calendar calendar) : base(calendar) { }
public override List<Type> SupportedTypes { get { return new List<Type>() { typeof(MyCustomItem) }; } }
public override IDictionary<string, object> Serialize(object obj, System.Web.Script.Serialization.JavaScriptSerializer serializer) { MyCustomItem item = obj as MyCustomItem; if (item != null) { IDictionary<string, object> json = base.Serialize(obj, serializer); if (json != null) { json.Add("recordedValue", item.RecordedValue); return json; } } return null; } } |
Visual Basic
Copy Code
|
---|
Imports MindFusion.Scheduling.WebForms
Class MyCustomItemConverter Inherits ItemConverter Public Sub New(calendar As Calendar) MyBase.New(calendar) End Sub
Public Overrides ReadOnly Property SupportedTypes() As List(Of Type) Get Return New List(Of Type)(New Type() {GetType(MyCustomItem)}) End Get End Property
Public Overrides Function Serialize(obj As Object, serializer As System.Web.Script.Serialization.JavaScriptSerializer) As IDictionary(Of String, Object) Dim item As MyCustomItem = TryCast(obj, MyCustomItem) If item IsNot Nothing Then Dim json As IDictionary(Of String, Object) = MyBase.Serialize(obj, serializer) If json IsNot Nothing Then json.Add("recordedValue", item.RecordedValue) Return json End If End If Return Nothing End Function End Class |
After you have created your custom JavaScriptConverter, you must register it for serialization with the Schedule, by handling the ItemSerialization event of the Calendar class:
C#
Copy Code
|
---|
// ...
Calendar1.ItemSerialization += new EventHandler<SerializationEventArgs>(Calendar1_ItemSerialization);
// ...
protected void Calendar1_ItemSerialization(object sender, SerializationEventArgs e) { e.Serializer.RegisterConverters(new JavaScriptConverter[] { new MyCustomItemConverter(Calendar1) }); } |
Visual Basic
Copy Code
|
---|
' ...
AddHandler Calendar1.ItemSerialization, AddressOf Calendar1_ItemSerialization
' ...
Protected Sub Calendar1_ItemSerialization(sender As Object, e As SerializationEventArgs) e.Serializer.RegisterConverters(New JavaScriptConverter() {New MyCustomItemConverter(Calendar1)}) End Sub |
Now, all you need to do is crate a new instance of your custom item and add it to the Schedule.Items collection.
C#
Copy Code
|
---|
MyCustomItem myItem = new MyCustomItem(); myItem.StartTime = DateTime.Today; myItem.EndTime = myItem.StartTime.AddHours(10); myItem.HeaderText = "My Custom Item!"; myItem.RecordedValue = 42;
Calendar1.Schedule.Items.Add(myItem); |
Visual Basic
Copy Code
|
---|
Dim myItem As New MyCustomItem() myItem.StartTime = DateTime.Today myItem.EndTime = myItem.StartTime.AddHours(10) myItem.HeaderText = "My Custom Item!" myItem.RecordedValue = 42
Calendar1.Schedule.Items.Add(myItem) |
Then you can read the value stored in RecordedValue:
JavaScript
Copy Code
|
---|
function showRecordedValue() { var calendar = $find('Calendar1');
var myCustomItem = calendar.getItems()[0]; alert(['This is my custom value: ', myCustomItem.recordedValue]); } |
Resources
The same pattern can be followed in order to use custom resource classes with MindFusion.Scheduling for WebForms.
The following is a full example on how to create a custom resource class:
ASPX
Copy Code
|
---|
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CustomResourceSample._Default" %> <%@ Register Assembly="MindFusion.Scheduling.WebForms" Namespace="MindFusion.Scheduling.WebForms" TagPrefix="MindFusion" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Custom Resources</title> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <div> <MindFusion:Calendar ID="Calendar1" runat="server" Height="600px" Width="800px" OnResourceSerialization="Calendar1_ResourceSerialization"> </MindFusion:Calendar> </div> </form> </body> |
C#
Copy Code
|
---|
using System; using System.Collections.Generic; using System.Web.Script.Serialization; using MindFusion.Scheduling; using MindFusion.Scheduling.WebForms;
namespace CustomResourceSample { public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (Schedule.IsClassRegistered("customres")) Schedule.UnregisterClass("customres"); Schedule.RegisterResourceClass(typeof(MyCustomResource), "customres", 1);
if (!IsPostBack) { MyCustomResource myResource = new MyCustomResource(); myResource.Name = "myresource"; myResource.ResourceDescription = "Short description of my resource.";
Calendar1.Schedule.Resources.Add(myResource);
Appointment myResourceHolder = new Appointment(); myResourceHolder.StartTime = DateTime.Now; myResourceHolder.EndTime = myResourceHolder.StartTime.AddHours(2); myResourceHolder.HeaderText = "Item with custom resource"; myResourceHolder.Resources.Add(myResource);
Calendar1.Schedule.Items.Add(myResourceHolder); } }
protected void Calendar1_ResourceSerialization(object sender, SerializationEventArgs e) { e.Serializer.RegisterConverters(new JavaScriptConverter[] { new MyCustomResourceConverter(Calendar1) }); } }
class MyCustomResource : Resource { public MyCustomResource() : base() { }
public string ResourceDescription { get; set; }
public override object SaveViewState() { if (!String.IsNullOrEmpty(ResourceDescription)) ViewState["_resourceDescription"] = ResourceDescription; return base.SaveViewState(); }
public override void LoadViewState(object state) { base.LoadViewState(state); if (ViewState["_resourceDescription"] != null) ResourceDescription = ViewState["_resourceDescription"].ToString(); }
public override void SaveTo(System.Xml.XmlElement element, XmlSerializationContext context) { base.SaveTo(element, context); context.WriteString(ResourceDescription, "ResourceDescription", element); }
public override void LoadFrom(System.Xml.XmlElement element, XmlSerializationContext context) { base.LoadFrom(element, context); ResourceDescription = context.ReadString("ResourceDescription", element); } }
class MyCustomResourceConverter : ResourceConverter { public MyCustomResourceConverter(Calendar calendar) : base(calendar) { }
public override IEnumerable<Type> SupportedTypes { get { return new List<Type>() { typeof(MyCustomResource) }; } }
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { MyCustomResource resource = obj as MyCustomResource; if (resource != null) { IDictionary<string, object> json = base.Serialize(obj, serializer); if (json != null) { if (!String.IsNullOrEmpty(resource.ResourceDescription)) json.Add("resourceDescription", resource.ResourceDescription); return json; } } return null; } } } |
Visual Basic
Copy Code
|
---|
Imports System.Collections.Generic Imports System.Web.Script.Serialization Imports MindFusion.Scheduling Imports MindFusion.Scheduling.WebForms
Public Partial Class _Default Inherits System.Web.UI.Page
Protected Sub Page_Load(sender As Object, e As EventArgs) If Schedule.IsClassRegistered("customres") Then Schedule.UnregisterClass("customres") End If Schedule.RegisterResourceClass(GetType(MyCustomResource), "customres", 1)
If Not IsPostBack Then Dim myResource As New MyCustomResource() myResource.Name = "myresource" myResource.ResourceDescription = "Short description of my resource."
Calendar1.Schedule.Resources.Add(myResource)
Dim myResourceHolder As New Appointment() myResourceHolder.StartTime = DateTime.Now myResourceHolder.EndTime = myResourceHolder.StartTime.AddHours(2) myResourceHolder.HeaderText = "Item with custom resource" myResourceHolder.Resources.Add(myResource)
Calendar1.Schedule.Items.Add(myResourceHolder) End If End Sub
Protected Sub Calendar1_ResourceSerialization(sender As Object, e As SerializationEventArgs) e.Serializer.RegisterConverters(New JavaScriptConverter() {New MyCustomResourceConverter(Calendar1)}) End Sub End Class Class MyCustomResource Inherits Resource
Public Sub New() MyBase.New() End Sub
Public Property ResourceDescription() As String Get Return description End Get Set(ByVal value As String) description = Value End Set End Property Private description As String
Public Overrides Function SaveViewState() As Object If Not [String].IsNullOrEmpty(ResourceDescription) Then ViewState("_resourceDescription") = ResourceDescription End If Return MyBase.SaveViewState() End Function
Public Overrides Sub LoadViewState(state As Object) MyBase.LoadViewState(state) If ViewState("_resourceDescription") IsNot Nothing Then ResourceDescription = ViewState("_resourceDescription").ToString() End If End Sub
Public Overrides Sub SaveTo(element As System.Xml.XmlElement, context As XmlSerializationContext) MyBase.SaveTo(element, context) context.WriteString(ResourceDescription, "ResourceDescription", element) End Sub
Public Overrides Sub LoadFrom(element As System.Xml.XmlElement, context As XmlSerializationContext) MyBase.LoadFrom(element, context) ResourceDescription = context.ReadString("ResourceDescription", element) End Sub End Class Class MyCustomResourceConverter Inherits ResourceConverter Public Sub New(calendar As Calendar) MyBase.New(calendar) End Sub
Public Overrides ReadOnly Property SupportedTypes() As IEnumerable(Of Type) Get Return New List(Of Type)(New Type() {GetType(MyCustomResource)}) End Get End Property
Public Overrides Function Serialize(obj As Object, serializer As JavaScriptSerializer) As IDictionary(Of String, Object) Dim resource As MyCustomResource = TryCast(obj, MyCustomResource) If resource IsNot Nothing Then Dim json As IDictionary(Of String, Object) = MyBase.Serialize(obj, serializer) If json IsNot Nothing Then If Not [String].IsNullOrEmpty(resource.ResourceDescription) Then json.Add("resourceDescription", resource.ResourceDescription) End If Return json End If End If Return Nothing End Function End Class |