Hi, I am working on a calendar project using .NET framework and is running into a horrible performance issue when working with dates. The issue is that whenever I want to retrieve all the events and to-dos occurring on a particular date, I have to transverse the entire list of events and to-dos checking which events and/or to-dos occur on that date. The problem gets worse when I work with project tasks as well. Thus, it is 3 O(n).
Typically, in this kind of situation, I would use a sorted binary tree data structure as storage rather than a list, but I don't know how to sort them when recurrence occurs. Thus, I need some recommendation on how I can improve the performance for retrieving all items occurring on a particular date. Also, this data structure must be able to handle situation when events' and/or to-dos' date is changed.
It is kind of hard to show just only relevant details about the project without overwhelming this question with details, but I will give it a try. I am integrating currently four different components together:
-
MonthCalendar class library
-
DDay.iCal class library for using iCal file
- Microsoft Office Project 12.0 Object Library
-
Plug-In Framework
Microsoft Office Project 12.0 Object Library will be applied via one of the plug-ins. What is events, to-dos, and recurrence is explained in details on this
standard. A simple and short version summary can be found on
Wikipedia.
Using the event handler, every time I select a date on MonthCalendar, execute the following:
private void calendar_DaySelected(object sender, DaySelectedEventArgs e)
{
DateTime date = DateTime.Parse(e.Days[0]);
schedulePanel.EventList.Clear();
schedulePanel.EventList.AddRange(calendarPanel.Calendar.GetDateInfo(date));
schedulePanel.TodoList.Clear();
schedulePanel.TodoList.AddRange(todoPanel.GetDateInfo(date));
if (projectPlugins.Count > 0)
{
schedulePanel.Tasks.Clear();
for (int i = 0; i < projectPlugins.Count; i++)
{
schedulePanel.Tasks.AddRange(projectPlugins[i].GetDateInfo(date));
}
}
schedulePanel.Update(date);
}
Here is the partial class code for SchedulePanel:
public SchedulePanel()
{
InitializeComponent();
eventList = new List<Library.DateItem>();
taskList = new List<PluginSDK.ITask>();
todoList = new List<ITodo>();
}
public void Update(DateTime date)
{
Text = "Schedule for " + date.ToShortDateString();
eventGridView.Rows.Clear();
for (int i = 0; i < eventList.Count; i++)
{
eventGridView.Rows.Add();
eventGridView.Rows[i].Cells[0].Value = eventList[i].Event.Summary;
}
if (taskList.Count != 0)
{
if (!this.Controls.Contains(this.taskBox))
{
this.Controls.Add(this.taskBox);
this.todoBox.Location = new System.Drawing.Point(3, 232);
this.todoBox.Size = new System.Drawing.Size(193, 116);
}
taskListBox.Items.Clear();
for (int j = 0; j < taskList.Count; j++)
{
taskListBox.Items.Add(taskList[j].Name);
}
}
else
{
if (this.Controls.Contains(this.taskBox))
{
this.Controls.Remove(this.taskBox);
this.todoBox.Location = new System.Drawing.Point(3, 103);
this.todoBox.Size = new System.Drawing.Size(193, 236);
}
}
todoListBox.Items.Clear();
for (int i = 0; i < todoList.Count; i++)
{
todoListBox.Items.Add(todoList[i].Summary);
}
}
public List<Library.DateItem> EventList
{
get
{
return eventList;
}
}
public List<ITodo> TodoList
{
get
{
return todoList;
}
}
public List<PluginSDK.ITask> Tasks
{
get
{
return taskList;
}
}
Here is the partial class code for TodoPanel:
public List<ITodo> GetDateInfo(DateTime date)
{
List<ITodo> todos = new List<ITodo>();
for (int i = 0; i < todoList.Count; i++)
{
if (todoList[i].Status != TodoStatus.Completed)
{
if (todoList[i].Start != null && todoList[i].Start.Date <= date)
todos.Add(todoList[i]);
else if (todoList[i].Due != null && todoList[i].Due.Date <= date)
todos.Add(todoList[i]);
}
}
return todos;
}
Here is the partial class code for MSProjectPanel using Microsoft Office Project 12.0 Object Library:
public List<ITask> GetDateInfo(DateTime date)
{
List<ITask> tasks = new List<ITask>();
foreach (Project project in application.Projects)
{
foreach (Task task in project.Tasks)
{
if (task.OutlineChildren.Count == 0 && task.Status != PjStatusType.pjComplete)
{
if (CompletePrerequisite(task) && DateTime.Parse(task.Start.ToString()) <= date)
{
tasks.Add(new ProjectTask(task));
}
}
}
}
return tasks;
}
It takes about 3+ seconds to finish executing after selecting a new date on 2.16GHz computer running Microsoft XP Professional with 512 MB of RAM. Currently, I am using 3 iCal files and 2 MPP files. That should be about 150+ items (events, to-dos, and 100+ project tasks) combined. Without MSProject plugin, it drops down to 1+ second.