private static void SetFormat(DependencyObject obj, DependencyPropertyChangedEventArgs args) { TimeSpanPicker timeSpanPicker = (TimeSpanPicker)obj; timeSpanPicker.parts.Clear(); IndexedDateTimePart currentPart = null; char previousFormatCharacter = '\0'; for (int formatIndex = 0, selectionIndex = 0; formatIndex < timeSpanPicker.Format.Length; ++formatIndex, ++selectionIndex) { char formatCharacter = timeSpanPicker.Format[formatIndex]; switch (formatCharacter) { case 'd': // days case 'f': // milliseconds case 'F': case 'h': // hours case 'm': // minutes case 's': // seconds break; case '\\': // backslashes aren't displayed and hence aren't part of selection --selectionIndex; continue; case '.': case ':': case ' ': // skip delimiters and spaces continue; default: throw new NotSupportedException(String.Format("Unsupported format character '{0}'.", formatCharacter)); } if (formatCharacter != previousFormatCharacter) { // encountered new part currentPart = new IndexedDateTimePart(formatCharacter, formatIndex, selectionIndex); timeSpanPicker.parts.Add(currentPart); previousFormatCharacter = formatCharacter; } else { // still in same part ++currentPart.FormatLength; ++currentPart.SelectionLength; } } // the first part may have a minus sign and therefore has variable selection indicies if (timeSpanPicker.parts.Count > 0) { timeSpanPicker.parts[0].IsSelectionStartVariable = true; } // ensure part index is valid if (timeSpanPicker.parts.Count < 1) { timeSpanPicker.currentPartIndex = -1; } else if (timeSpanPicker.currentPartIndex < 0) { timeSpanPicker.currentPartIndex = 0; } else if (timeSpanPicker.currentPartIndex > timeSpanPicker.parts.Count - 1) { timeSpanPicker.currentPartIndex = timeSpanPicker.parts.Count - 1; } // ensure displayed value uses current format timeSpanPicker.TimeSpanDisplay.Text = timeSpanPicker.Value.ToString(timeSpanPicker.Format); }
private static void SetFormat(DependencyObject obj, DependencyPropertyChangedEventArgs args) { DateTimeOffsetPicker dateTimeOffsetPicker = (DateTimeOffsetPicker)obj; dateTimeOffsetPicker.monthPartIndex = Int32.MaxValue; dateTimeOffsetPicker.parts.Clear(); IndexedDateTimePart currentPart = null; char previousFormatCharacter = '\0'; for (int formatIndex = 0, selectionIndex = 0; formatIndex < dateTimeOffsetPicker.Format.Length; ++formatIndex, ++selectionIndex) { char formatCharacter = dateTimeOffsetPicker.Format[formatIndex]; switch (formatCharacter) { case 'd': // day case 'f': // millisecond case 'F': case 'h': // hour case 'H': case Constant.Time.DateTimeOffsetPart: // offset case 'm': // minute case 'M': // month case 's': // second case 'y': // year case 'z': // offset break; case '\\': // backslashes aren't displayed and hence aren't part of selection --selectionIndex; continue; case '.': case ':': case '/': case '-': case ' ': case 'T': case 'Z': // skip delimiters and UTC indicator continue; default: throw new NotSupportedException(String.Format("Unsupported format character '{0}'.", formatCharacter)); } if (formatCharacter != previousFormatCharacter) { if ((currentPart != null) && (currentPart.Format == 'M') && (currentPart.FormatLength == 3)) { // part which just ended is an MMM month part and may render as two to eight or more characters depending on the current culture // If needed this check can be done after the loop completes but there's no scenario for putting the month at the end of the date or // not following it with some other part. Lengths of zero are excluded as most calendars have 12 months. List<int> abbreviatedMonthNameLengths = CultureInfo.CurrentCulture.DateTimeFormat.AbbreviatedMonthNames.Select(name => name.Length).Distinct().Where(length => length > 0).ToList(); int minimumSelectionLength = abbreviatedMonthNameLengths.Min(); currentPart.IsSelectionLengthVariable = abbreviatedMonthNameLengths.Count > 1; currentPart.SelectionLength = minimumSelectionLength; dateTimeOffsetPicker.monthPartIndex = dateTimeOffsetPicker.parts.Count - 1; selectionIndex += minimumSelectionLength - 3; } // encountered new part currentPart = new IndexedDateTimePart(formatCharacter, formatIndex, selectionIndex); dateTimeOffsetPicker.parts.Add(currentPart); previousFormatCharacter = formatCharacter; if (formatCharacter == Constant.Time.DateTimeOffsetPart) { // current part is hours part, which may have a minus sign and therefore has a variable start currentPart.IsSelectionStartVariable = true; currentPart.SelectionLength = 2; // add minutes part IndexedDateTimePart minutesPart = new IndexedDateTimePart(formatCharacter, formatIndex, currentPart.SelectionStart + currentPart.SelectionLength + 1) { SelectionLength = 2 }; dateTimeOffsetPicker.parts.Add(minutesPart); } } else { // still in same part ++currentPart.FormatLength; ++currentPart.SelectionLength; } } // ensure part index is valid if (dateTimeOffsetPicker.parts.Count < 1) { dateTimeOffsetPicker.currentPartIndex = -1; } else if (dateTimeOffsetPicker.currentPartIndex < 0) { dateTimeOffsetPicker.currentPartIndex = 0; } else if (dateTimeOffsetPicker.currentPartIndex > dateTimeOffsetPicker.parts.Count - 1) { dateTimeOffsetPicker.currentPartIndex = dateTimeOffsetPicker.parts.Count - 1; } // ensure displayed value uses current format dateTimeOffsetPicker.DateTimeDisplay.Text = dateTimeOffsetPicker.Value.ToString(dateTimeOffsetPicker.Format); }