public static MarkupExtensionInfo Parse(string input) { #region Parameter Checks if (!MarkupExtensionPattern.IsMatch(input)) { string msg = String.Format("{0} is not a MarkupExtension.", input); throw new InvalidOperationException(msg); } #endregion Parameter Checks var resultInfo = new MarkupExtensionInfo(); using (var reader = new StringReader(input)) { var parsingMode = MarkupExtensionParsingModeEnum.START; try { //Debug.Print("Parsing '{0}'", input); //Debug.Indent(); while (MarkupExtensionParsingModeEnum.END != parsingMode && MarkupExtensionParsingModeEnum.UNEXPECTED != parsingMode) { //Debug.Print(context.ToString()); //Debug.Indent(); switch (parsingMode) { case MarkupExtensionParsingModeEnum.START: parsingMode = reader.ReadMarkupExtensionStart(); break; case MarkupExtensionParsingModeEnum.MARKUP_NAME: parsingMode = reader.ReadMarkupName(resultInfo); break; case MarkupExtensionParsingModeEnum.NAME_VALUE_PAIR: parsingMode = reader.ReadNameValuePair(resultInfo); break; } //Debug.Unindent(); } } catch (Exception exp) { throw new InvalidDataException( String.Format("Cannot parse markup extension string:\r\n \"{0}\"", input), exp); } } return resultInfo; }
private static MarkupExtensionParsingModeEnum ReadNameValuePair(this StringReader reader, MarkupExtensionInfo info) { string methodName = MethodBase.GetCurrentMethod().Name; char[] stopChars = {',', '=', '}'}; MarkupExtensionParsingModeEnum resultParsingMode; string key = null; object value = null; reader.SeekTill(x => !Char.IsWhiteSpace(x)); // When '{' is the starting char, the following must be a value instead of a key. // // E.g., // <Setter x:Uid="Setter_75" // Property="Foreground" // Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" /> // // In other words, "key" shall not start with '{', as it won't be a valid property name. if ('{' != reader.PeekChar()) { string temp = reader.ReadTill(stopChars.Contains).Trim(); char keyValueIndicatorChar = reader.PeekChar(); switch (keyValueIndicatorChar) { case ',': case '}': value = temp; break; case '=': key = temp; // Consume the '=' reader.Read(); break; default: throw new InvalidDataException( String.Format("[{0}] Should not encounter '{1}'.", methodName, keyValueIndicatorChar)); } } if (null == value) { reader.SeekTill(x => !(Char.IsWhiteSpace(x))); string input = reader.ReadValueString().Trim(); if (MarkupExtensionPattern.IsMatch(input)) { value = Parse(input); } else { value = input; } } if (String.IsNullOrEmpty(key)) { info.ValueOnlyProperties.Add(value); } else { info.KeyValueProperties.Add(new KeyValuePair<string, object>(key, value)); } reader.SeekTill(x => !Char.IsWhiteSpace(x)); char stopChar = reader.ReadChar(); switch (stopChar) { case ',': resultParsingMode = MarkupExtensionParsingModeEnum.NAME_VALUE_PAIR; break; case '}': resultParsingMode = MarkupExtensionParsingModeEnum.END; break; default: throw new InvalidDataException( String.Format("[{0}] Should not encounter '{1}'.", methodName, stopChar)); } if (MarkupExtensionParsingModeEnum.UNEXPECTED == resultParsingMode) { throw new InvalidDataException( String.Format("[{0}] Invalid result context: {1}", methodName, resultParsingMode)); } return resultParsingMode; }
private static MarkupExtensionParsingModeEnum ReadMarkupName(this StringReader reader, MarkupExtensionInfo info) { string methodName = MethodBase.GetCurrentMethod().Name; char[] stopChars = {' ', '}'}; var resultParsingMode = MarkupExtensionParsingModeEnum.UNEXPECTED; var buffer = new StringBuilder(); while (!reader.IsEnd()) { char c = reader.ReadChar(); if (stopChars.Contains(c)) { switch (c) { case ' ': resultParsingMode = MarkupExtensionParsingModeEnum.NAME_VALUE_PAIR; break; case '}': resultParsingMode = MarkupExtensionParsingModeEnum.END; break; default: throw new InvalidDataException( String.Format("[{0}] Should not encounter '{1}'.", methodName, c)); } info.Name = buffer.ToString().Trim(); buffer.Clear(); // break out the while break; } buffer.Append(c); } if (MarkupExtensionParsingModeEnum.UNEXPECTED == resultParsingMode) { throw new InvalidDataException( String.Format("[{0}] Invalid result context: {1}", methodName, resultParsingMode)); } return resultParsingMode; }