//===================================================================== /// <summary> /// This is overridden to allow cloning of a PDI object /// </summary> /// <returns>A clone of the object</returns> public override object Clone() { VToDo o = new VToDo(); o.Clone(this); return(o); }
/// <summary> /// This is overridden to allow proper comparison of To-Do objects /// </summary> /// <param name="obj">The object to which this instance is compared</param> /// <returns>Returns true if the object equals this instance, false if it does not</returns> public override bool Equals(object obj) { VToDo td = obj as VToDo; if (td == null) { return(false); } // The ToString() method returns a text representation of the object based on all of its settings so // it's a reliable way to tell if two instances are the same. return(this == td || this.ToString() == td.ToString()); }
/// <summary> /// This is overridden to allow copying of the additional properties /// </summary> /// <param name="p">The PDI object from which the settings are to be copied</param> protected override void Clone(PDIObject p) { VToDo o = (VToDo)p; this.ClearProperties(); classification = (ClassificationProperty)o.Classification.Clone(); categories = (CategoriesProperty)o.Categories.Clone(); resources = (ResourcesProperty)o.Resources.Clone(); url = (UrlProperty)o.Url.Clone(); uid = (UniqueIdProperty)o.UniqueId.Clone(); geo = (GeographicPositionProperty)o.GeographicPosition.Clone(); lastMod = (LastModifiedProperty)o.LastModified.Clone(); dateCreated = (DateCreatedProperty)o.DateCreated.Clone(); startDate = (StartDateProperty)o.StartDateTime.Clone(); due = (DueDateProperty)o.DueDateTime.Clone(); completed = (CompletedDateProperty)o.CompletedDateTime.Clone(); timeStamp = (TimeStampProperty)o.TimeStamp.Clone(); summary = (SummaryProperty)o.Summary.Clone(); desc = (DescriptionProperty)o.Description.Clone(); priority = (PriorityProperty)o.Priority.Clone(); sequence = (SequenceProperty)o.Sequence.Clone(); rNum = (RecurrenceCountProperty)o.RecurrenceCount.Clone(); comment = (CommentProperty)o.Comment.Clone(); organizer = (OrganizerProperty)o.Organizer.Clone(); recurId = (RecurrenceIdProperty)o.RecurrenceId.Clone(); status = (StatusProperty)o.Status.Clone(); pct = (PercentCompleteProperty)o.PercentComplete.Clone(); duration = (DurationProperty)o.Duration.Clone(); this.Contacts.CloneRange(o.Contacts); this.Attendees.CloneRange(o.Attendees); this.RelatedTo.CloneRange(o.RelatedTo); this.Attachments.CloneRange(o.Attachments); this.RequestStatuses.CloneRange(o.RequestStatuses); this.Alarms.CloneRange(o.Alarms); this.CustomProperties.CloneRange(o.CustomProperties); base.Clone(p); }
/// <summary> /// Add a calendar item /// </summary> /// <param name="sender">The sender of the event</param> /// <param name="e">The event arguments</param> private void btnAdd_Click(object sender, EventArgs e) { switch(cboComponents.SelectedIndex) { case 0: using(CalendarObjectDlg dlg = new CalendarObjectDlg()) { VEvent evt = new VEvent(); evt.UniqueId.AssignNewId(true); evt.DateCreated.TimeZoneDateTime = DateTime.Now; evt.LastModified.TimeZoneDateTime = evt.DateCreated.TimeZoneDateTime; dlg.SetValues(evt); if(dlg.ShowDialog() == DialogResult.OK) { dlg.GetValues(evt); // Create a unique ID for the new item evt.UniqueId.AssignNewId(true); vCal.Events.Add(evt); } } break; case 1: using(CalendarObjectDlg dlg = new CalendarObjectDlg()) { VToDo td = new VToDo(); td.DateCreated.TimeZoneDateTime = DateTime.Now; td.LastModified.TimeZoneDateTime = td.DateCreated.TimeZoneDateTime; dlg.SetValues(td); if(dlg.ShowDialog() == DialogResult.OK) { dlg.GetValues(td); // Create a unique ID for the new item td.UniqueId.AssignNewId(true); vCal.ToDos.Add(td); } } break; case 2: using(CalendarObjectDlg dlg = new CalendarObjectDlg()) { VJournal j = new VJournal(); j.DateCreated.TimeZoneDateTime = DateTime.Now; j.LastModified.TimeZoneDateTime = j.DateCreated.TimeZoneDateTime; dlg.SetValues(j); if(dlg.ShowDialog() == DialogResult.OK) { dlg.GetValues(j); // Create a unique ID for the new item j.UniqueId.AssignNewId(true); vCal.Journals.Add(j); } } break; case 3: using(VFreeBusyDlg dlg = new VFreeBusyDlg()) { if(dlg.ShowDialog() == DialogResult.OK) { VFreeBusy fb = new VFreeBusy(); dlg.GetValues(fb); // Create a unique ID for the new item fb.UniqueId.AssignNewId(true); vCal.FreeBusys.Add(fb); } } break; } }
/// <summary> /// Store To-Do information from the controls /// </summary> /// <param name="td">The To-Do to use</param> private bool StoreToDoInfo(VToDo td) { DateTime startDate = DateTime.MinValue, endDate = DateTime.MinValue, completedDate = DateTime.MinValue; Duration dur = Duration.Zero; lblMsg.Text = null; // Perform some edits if(txtStartDate.Text.Trim().Length != 0 && !DateTime.TryParse(txtStartDate.Text, CultureInfo.CurrentCulture, DateTimeStyles.None, out startDate)) lblMsg.Text = "Invalid start date format<br>"; if(txtEndDate.Text.Trim().Length != 0 && !DateTime.TryParse(txtEndDate.Text, CultureInfo.CurrentCulture, DateTimeStyles.None, out endDate)) lblMsg.Text = "Invalid end date format<br>"; if(txtCompleted.Text.Trim().Length != 0 && !DateTime.TryParse(txtCompleted.Text, CultureInfo.CurrentCulture, DateTimeStyles.None, out completedDate)) lblMsg.Text = "Invalid completed date format<br>"; if(txtDuration.Text.Trim().Length != 0 && !Duration.TryParse(txtDuration.Text, out dur)) lblMsg.Text += "Invalid duration format<br>"; if(!String.IsNullOrWhiteSpace(lblMsg.Text)) return false; // Unique ID is not changed td.LastModified.TimeZoneDateTime = DateTime.Now; if(txtSequence.Text.Trim().Length == 0) td.Sequence.SequenceNumber = 0; else td.Sequence.SequenceNumber = Convert.ToInt32(txtSequence.Text); if(txtPriority.Text.Trim().Length == 0) td.Priority.PriorityValue = 0; else td.Priority.PriorityValue = Convert.ToInt32(txtPriority.Text); td.StartDateTime.TimeZoneDateTime = startDate; td.StartDateTime.ValueLocation = ValLocValue.DateTime; td.DueDateTime.TimeZoneDateTime = endDate; td.DueDateTime.ValueLocation = ValLocValue.DateTime; td.CompletedDateTime.TimeZoneDateTime = completedDate; td.CompletedDateTime.ValueLocation = ValLocValue.DateTime; if(txtPercent.Text.Trim().Length == 0) td.PercentComplete.Percentage = 0; else td.PercentComplete.Percentage = Convert.ToInt32(txtPercent.Text); td.Duration.DurationValue = dur; td.Summary.Value = txtSummary.Text; td.Description.Value = txtDescription.Text; td.Organizer.Value = txtOrganizer.Text; td.Url.Value = txtUrl.Text; td.Comment.Value = txtComments.Text; // Get status value td.Status.StatusValue = (StatusValue)Enum.Parse(typeof(StatusValue), cboStatus.Items[cboStatus.SelectedIndex].ToString(), true); return true; }
/// <summary> /// Load To-Do information into the controls /// </summary> /// <param name="td">The To-Do to use</param> private void LoadToDoInfo(VToDo td) { chkTransparent.Enabled = txtLocation.Enabled = false; lblEndDate.Text = "Due"; lblUniqueId.Text = td.UniqueId.Value; lblTimeZone.Text = td.StartDateTime.TimeZoneId; txtSequence.Text = td.Sequence.SequenceNumber.ToString(); txtPriority.Text = td.Priority.PriorityValue.ToString(); // General if(td.StartDateTime.TimeZoneDateTime != DateTime.MinValue) txtStartDate.Text = td.StartDateTime.TimeZoneDateTime.ToString("G"); // We'll reuse End Date for Due Date if(td.DueDateTime.TimeZoneDateTime != DateTime.MinValue) txtEndDate.Text = td.DueDateTime.TimeZoneDateTime.ToString("G"); if(td.CompletedDateTime.TimeZoneDateTime != DateTime.MinValue) txtCompleted.Text = td.CompletedDateTime.TimeZoneDateTime.ToString("G"); if(td.Duration.DurationValue != Duration.Zero) txtDuration.Text = td.Duration.DurationValue.ToString(Duration.MaxUnit.Weeks); txtPercent.Text = td.PercentComplete.Percentage.ToString(); txtSummary.Text = td.Summary.Value; txtDescription.Text = td.Description.Value; txtOrganizer.Text = td.Organizer.Value; txtUrl.Text = td.Url.Value; txtComments.Text = td.Comment.Value; // Load status values and set status cboStatus.Items.Add("None"); cboStatus.Items.Add("NeedsAction"); cboStatus.Items.Add("Completed"); cboStatus.Items.Add("InProcess"); cboStatus.Items.Add("Cancelled"); if(cboStatus.Items.FindByValue(td.Status.StatusValue.ToString()) == null) cboStatus.Items.Add(td.Status.StatusValue.ToString()); cboStatus.SelectedValue = td.Status.StatusValue.ToString(); dgAttendees.DataSource = td.Attendees; dgRecurrences.DataSource = td.RecurrenceRules; dgRecurDates.DataSource = td.RecurDates; dgExceptions.DataSource = td.ExceptionRules; dgExDates.DataSource = td.ExceptionDates; dgReqStats.DataSource = td.RequestStatuses; }
//===================================================================== /// <summary> /// This is overridden to allow cloning of a PDI object /// </summary> /// <returns>A clone of the object</returns> public override object Clone() { VToDo o = new VToDo(); o.Clone(this); return o; }
/// <summary> /// This is implemented to handle properties as they are parsed from the data stream /// </summary> /// <param name="propertyName">The name of the property.</param> /// <param name="parameters">A string collection containing the parameters and their values. If empty, /// there are no parameters.</param> /// <param name="propertyValue">The value of the property.</param> /// <remarks><para>There may be a mixture of name/value pairs or values alone in the parameters string /// collection. It is up to the derived class to process the parameter list based on the specification /// to which it conforms. For entries that are parameter names, the entry immediately following it in /// the collection is its associated parameter value. The property name, parameter names, and their /// values may be in upper, lower, or mixed case.</para> /// /// <para>The value may be an encoded string. The properties are responsible for any decoding that may /// need to occur (i.e. base 64 encoded image data).</para></remarks> /// <exception cref="PDIParserException">This is thrown if an error is encountered while parsing the data /// stream. Refer to the and inner exceptions for information on the cause of the problem.</exception> protected override void PropertyParser(string propertyName, StringCollection parameters, string propertyValue) { SpecificationVersions version = SpecificationVersions.None; string temp; int idx; // Is it parsing a sub-object? if(currentState != VCalendarParserState.VCalendar) { switch(currentState) { case VCalendarParserState.VEvent: VEventParser(propertyName, parameters, propertyValue); break; case VCalendarParserState.VToDo: VToDoParser(propertyName, parameters, propertyValue); break; case VCalendarParserState.VJournal: VJournalParser(propertyName, parameters, propertyValue); break; case VCalendarParserState.VAlarm: VAlarmParser(propertyName, parameters, propertyValue); break; case VCalendarParserState.VFreeBusy: VFreeBusyParser(propertyName, parameters, propertyValue); break; case VCalendarParserState.VTimeZone: VTimeZoneParser(propertyName, parameters, propertyValue); break; case VCalendarParserState.ObservanceRule: ObservanceRuleParser(propertyName, parameters, propertyValue); break; case VCalendarParserState.Custom: CustomObjectParser(propertyName, parameters, propertyValue); break; } return; } // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntvCal.Length - 1; idx++) if(ntvCal[idx].IsMatch(propertyName)) break; // An opening BEGIN:VCALENDAR property must have been seen if(vCal == null && ntvCal[idx].EnumValue != PropertyType.Begin) throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VCALENDAR", propertyName)); // Handle or create the property switch(ntvCal[idx].EnumValue) { case PropertyType.Begin: // Start a new object temp = propertyValue.Trim(); // The last entry is always Custom so scan for length - 1 for(idx = 0; idx < ntvObjs.Length - 1; idx++) if(ntvObjs[idx].IsMatch(temp)) break; priorState.Push(currentState); currentState = ntvObjs[idx].EnumValue; switch(currentState) { case VCalendarParserState.VCalendar: // NOTE: If serializing into an existing instance, this may not be null. If so, it // is ignored. It may also exist if two calendars appear in the same file. In that // case, they will be merged into one calendar. if(vCal == null) vCal = new VCalendar(); break; case VCalendarParserState.VEvent: vEvent = new VEvent(); vCal.Events.Add(vEvent); break; case VCalendarParserState.VToDo: vToDo = new VToDo(); vCal.ToDos.Add(vToDo); break; case VCalendarParserState.VJournal: vJournal = new VJournal(); vCal.Journals.Add(vJournal); break; case VCalendarParserState.VFreeBusy: vFreeBusy = new VFreeBusy(); vCal.FreeBusys.Add(vFreeBusy); break; case VCalendarParserState.VTimeZone: // NOTE: Unlike the other objects, time zone are not added to the collection until // the END Tag is encountered as they are shared amongst all calendar instances. vTimeZone = new VTimeZone(); break; case VCalendarParserState.Custom: CustomObjectParser(propertyName, parameters, propertyValue); break; } break; case PropertyType.End: // The value must be VCALENDAR if(String.Compare(propertyValue.Trim(), "VCALENDAR", StringComparison.OrdinalIgnoreCase) != 0) throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntvCal[idx].Name, propertyValue)); // When done, we'll propagate the version number to all objects to make it consistent vCal.PropagateVersion(); break; case PropertyType.Version: // Version must be 1.0 or 2.0 temp = propertyValue.Trim(); if(temp == "1.0") version = SpecificationVersions.vCalendar10; else if(temp == "2.0") version = SpecificationVersions.iCalendar20; else throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedVersion", "vCalendar/iCalendar", temp)); vCal.Version = version; break; case PropertyType.ProductId: vCal.ProductId.EncodedValue = propertyValue; break; case PropertyType.CalendarScale: vCal.CalendarScale.DeserializeParameters(parameters); vCal.CalendarScale.EncodedValue = propertyValue; break; case PropertyType.Method: vCal.Method.DeserializeParameters(parameters); vCal.Method.EncodedValue = propertyValue; break; case PropertyType.GeographicPosition: vCal.VCalendarGeographicPosition.EncodedValue = propertyValue; break; case PropertyType.TimeZone: vCal.VCalendarTimeZone.DeserializeParameters(parameters); vCal.VCalendarTimeZone.EncodedValue = propertyValue; break; case PropertyType.Daylight: vCal.VCalendarDaylightRule.DeserializeParameters(parameters); vCal.VCalendarDaylightRule.EncodedValue = propertyValue; break; default: // Anything else is a custom property CustomProperty c = new CustomProperty(propertyName); c.DeserializeParameters(parameters); c.EncodedValue = propertyValue; vCal.CustomProperties.Add(c); break; } }
//===================================================================== /// <summary> /// This is overridden to handle the additional state maintained by the calendar parser /// </summary> /// <param name="fullReset">If true, a full reset is done (i.e. this is the start of a brand new session. /// If false only the line state is reset (it's done parsing a property name or value).</param> protected override void ResetState(bool fullReset) { if(fullReset) { currentState = VCalendarParserState.VCalendar; vEvent = null; vToDo = null; vJournal = null; vAlarm = null; vFreeBusy = null; vTimeZone = null; obsRule = null; priorState.Clear(); beginValue.Clear(); } base.ResetState(fullReset); }
/// <summary> /// This is implemented to handle properties related to VToDo items /// </summary> /// <param name="propertyName">The name of the property.</param> /// <param name="parameters">A string collection containing the parameters and their values. If empty, /// there are no parameters.</param> /// <param name="propertyValue">The value of the property.</param> protected virtual void VToDoParser(string propertyName, StringCollection parameters, string propertyValue) { StringCollection sc; string[] parts, parms; int idx; // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntvToDo.Length - 1; idx++) if(ntvToDo[idx].IsMatch(propertyName)) break; // An opening BEGIN:VTODO property must have been seen if(vToDo == null) throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VTODO", propertyName)); // Handle or create the property switch(ntvToDo[idx].EnumValue) { case PropertyType.Begin: // Handle nested objects priorState.Push(currentState); // Is it an alarm? if(String.Compare(propertyValue.Trim(), "VALARM", StringComparison.OrdinalIgnoreCase) == 0) { vAlarm = new VAlarm(); vToDo.Alarms.Add(vAlarm); currentState = VCalendarParserState.VAlarm; } else { // Unknown/custom object currentState = VCalendarParserState.Custom; CustomObjectParser(propertyName, parameters, propertyValue); } break; case PropertyType.End: // For this, the value must be VTODO if(String.Compare(propertyValue.Trim(), "VTODO", StringComparison.OrdinalIgnoreCase) != 0) throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntvToDo[idx].Name, propertyValue)); // The To-Do is added to the collection when created so we don't have to rely on an END tag // to add it. vToDo = null; currentState = priorState.Pop(); break; case PropertyType.Class: vToDo.Classification.EncodedValue = propertyValue; break; case PropertyType.Categories: // If this is seen more than once, just add the new stuff to the existing property CategoriesProperty cp = new CategoriesProperty(); cp.DeserializeParameters(parameters); cp.EncodedValue = propertyValue; foreach(string s in cp.Categories) vToDo.Categories.Categories.Add(s); break; case PropertyType.Resources: // If this is seen more than once, just add the new stuff to the existing property ResourcesProperty rp = new ResourcesProperty(); rp.DeserializeParameters(parameters); rp.EncodedValue = propertyValue; foreach(string s in rp.Resources) vToDo.Resources.Resources.Add(s); break; case PropertyType.Url: vToDo.Url.DeserializeParameters(parameters); vToDo.Url.EncodedValue = propertyValue; break; case PropertyType.UniqueId: vToDo.UniqueId.EncodedValue = propertyValue; break; case PropertyType.LastModified: vToDo.LastModified.DeserializeParameters(parameters); vToDo.LastModified.EncodedValue = propertyValue; break; case PropertyType.GeographicPosition: vToDo.GeographicPosition.EncodedValue = propertyValue; break; case PropertyType.DateCreated: vToDo.DateCreated.DeserializeParameters(parameters); vToDo.DateCreated.EncodedValue = propertyValue; break; case PropertyType.DueDate: vToDo.DueDateTime.DeserializeParameters(parameters); vToDo.DueDateTime.EncodedValue = propertyValue; break; case PropertyType.StartDateTime: vToDo.StartDateTime.DeserializeParameters(parameters); vToDo.StartDateTime.EncodedValue = propertyValue; break; case PropertyType.CompletedDate: vToDo.CompletedDateTime.DeserializeParameters(parameters); vToDo.CompletedDateTime.EncodedValue = propertyValue; break; case PropertyType.TimeStamp: vToDo.TimeStamp.DeserializeParameters(parameters); vToDo.TimeStamp.EncodedValue = propertyValue; break; case PropertyType.Summary: vToDo.Summary.DeserializeParameters(parameters); vToDo.Summary.EncodedValue = propertyValue; break; case PropertyType.Description: vToDo.Description.DeserializeParameters(parameters); vToDo.Description.EncodedValue = propertyValue; break; case PropertyType.Priority: vToDo.Priority.DeserializeParameters(parameters); vToDo.Priority.EncodedValue = propertyValue; break; case PropertyType.Sequence: vToDo.Sequence.DeserializeParameters(parameters); vToDo.Sequence.EncodedValue = propertyValue; break; case PropertyType.RecurrenceCount: vToDo.RecurrenceCount.DeserializeParameters(parameters); vToDo.RecurrenceCount.EncodedValue = propertyValue; break; case PropertyType.Comment: // If this is seen more than once, just add the new stuff to the existing property if(vToDo.Comment.Value != null) { vToDo.Comment.EncodedValue += "\r\n"; vToDo.Comment.EncodedValue += propertyValue; } else { vToDo.Comment.DeserializeParameters(parameters); vToDo.Comment.EncodedValue = propertyValue; } break; case PropertyType.Contact: ContactProperty cont = new ContactProperty(); cont.DeserializeParameters(parameters); cont.EncodedValue = propertyValue; vToDo.Contacts.Add(cont); break; case PropertyType.Organizer: vToDo.Organizer.DeserializeParameters(parameters); vToDo.Organizer.EncodedValue = propertyValue; break; case PropertyType.Attendee: AttendeeProperty ap = new AttendeeProperty(); ap.DeserializeParameters(parameters); ap.EncodedValue = propertyValue; vToDo.Attendees.Add(ap); break; case PropertyType.RelatedTo: RelatedToProperty rt = new RelatedToProperty(); rt.DeserializeParameters(parameters); rt.EncodedValue = propertyValue; vToDo.RelatedTo.Add(rt); break; case PropertyType.Attachment: AttachProperty att = new AttachProperty(); att.DeserializeParameters(parameters); att.EncodedValue = propertyValue; vToDo.Attachments.Add(att); break; case PropertyType.RecurrenceId: vToDo.RecurrenceId.DeserializeParameters(parameters); vToDo.RecurrenceId.EncodedValue = propertyValue; break; case PropertyType.Status: vToDo.Status.DeserializeParameters(parameters); vToDo.Status.EncodedValue = propertyValue; break; case PropertyType.RequestStatus: RequestStatusProperty rs = new RequestStatusProperty(); rs.DeserializeParameters(parameters); rs.EncodedValue = propertyValue; vToDo.RequestStatuses.Add(rs); break; case PropertyType.PercentComplete: vToDo.PercentComplete.DeserializeParameters(parameters); vToDo.PercentComplete.EncodedValue = propertyValue; break; case PropertyType.Duration: vToDo.Duration.DeserializeParameters(parameters); vToDo.Duration.EncodedValue = propertyValue; break; case PropertyType.AudioAlarm: case PropertyType.DisplayAlarm: case PropertyType.EMailAlarm: case PropertyType.ProcedureAlarm: // These are converted to a VAlarm object vAlarm = new VAlarm(); ParseVCalendarAlarm(ntvToDo[idx].EnumValue, parameters, propertyValue); vToDo.Alarms.Add(vAlarm); vAlarm = null; break; case PropertyType.RecurrenceRule: RRuleProperty rr = new RRuleProperty(); rr.DeserializeParameters(parameters); rr.EncodedValue = propertyValue; vToDo.RecurrenceRules.Add(rr); break; case PropertyType.RecurDate: // There may be more than one date in the value. If so, split them into separate ones. This // makes it easier to manage. They'll get written back out as individual properties but // that's okay. parts = propertyValue.Split(',', ';'); // It's important that we retain the same parameters for each one parms = new string[parameters.Count]; parameters.CopyTo(parms, 0); foreach(string s in parts) { sc = new StringCollection(); sc.AddRange(parms); RDateProperty rd = new RDateProperty(); rd.DeserializeParameters(sc); rd.EncodedValue = s; vToDo.RecurDates.Add(rd); } break; case PropertyType.ExceptionRule: ExRuleProperty er = new ExRuleProperty(); er.DeserializeParameters(parameters); er.EncodedValue = propertyValue; vToDo.ExceptionRules.Add(er); break; case PropertyType.ExceptionDate: // There may be more than one date in the value. If so, split them into separate ones. This // makes it easier to manage. They'll get written back out as individual properties but // that's okay. parts = propertyValue.Split(',', ';'); // It's important that we retain the same parameters for each one parms = new string[parameters.Count]; parameters.CopyTo(parms, 0); foreach(string s in parts) { sc = new StringCollection(); sc.AddRange(parms); ExDateProperty ed = new ExDateProperty(); ed.DeserializeParameters(sc); ed.EncodedValue = s; vToDo.ExceptionDates.Add(ed); } break; case PropertyType.ExcludeStartDateTime: // This is a custom property not defined by the spec vToDo.ExcludeStartDateTime = (propertyValue[0] == '1'); break; default: // Anything else is a custom property CustomProperty cust = new CustomProperty(propertyName); cust.DeserializeParameters(parameters); cust.EncodedValue = propertyValue; vToDo.CustomProperties.Add(cust); break; } }