private static void AddMarkupValue(this Paragraph paragraph, string value, XamlStyles styles) { var markupString = value.Substring(1, value.Length - 2); var indexOfSpace = markupString.IndexOf(' '); var markupType = indexOfSpace < 0 ? markupString : markupString.Substring(0, indexOfSpace); paragraph.AddRun("{", styles.DelimiterStyle); paragraph.AddRun(markupType, styles.NameStyle); if (indexOfSpace >= 0) { paragraph.AddMarkupBody(markupString.Substring(indexOfSpace), styles); } paragraph.AddRun("}", styles.DelimiterStyle); }
private static void AddAttributeValue(this Paragraph paragraph, string value, XamlStyles styles) { if (value.StartsWith("{}")) { paragraph.AddRun(value, styles.TextStyle); } else if (value.StartsWith("{") && value.EndsWith("}")) { paragraph.AddMarkupValue(value, styles); } else { paragraph.AddRun(value, styles.AttributeValueStyle); } }
private static void AddMarkupBody(this Paragraph paragraph, string value, XamlStyles styles) { var indexOfNonspace = FindNonspaceInMarkup(value); var spaceText = indexOfNonspace < 0 ? value : value.Substring(0, indexOfNonspace); paragraph.AddRun(spaceText, styles.AttributeValueStyle); if (indexOfNonspace < 0) { return; } value = value.Substring(indexOfNonspace); if (value.StartsWith("{}")) { var indexOfComma = FindCommaInMarkup(value); var text = indexOfComma < 0 ? value : value.Substring(0, indexOfComma); paragraph.AddRun(text, styles.TextStyle); if (indexOfComma < 0) { return; } value = value.Substring(indexOfComma); } else if (value.StartsWith("{")) { var indexOfClosedBrace = FindClosedBraceInMarkup(value); if (indexOfClosedBrace < 0) { paragraph.AddRun(value, styles.ErrorStyle); return; } paragraph.AddMarkupValue(value.Substring(0, indexOfClosedBrace), styles); value = value.Substring(indexOfClosedBrace + 1); } // TODO: // Path=Title, StringFormat={}{0}AVS, ElementName=window paragraph.AddRun(value, styles.AttributeValueStyle); }
/// <summary> /// Fill flow document paragraph with syntax colored XAML. /// </summary> /// <param name="paragraph">paragraph to be filled</param> /// <param name="xaml">xaml to colorize</param> /// <param name="styles">styles used for syntax coloring</param> public static void FillParagraph(this Paragraph paragraph, string xaml, XamlStyles styles) { using (var reader = new XmlTextReader(xaml, XmlNodeType.Document, null)) { var indent = 0; var tagOpened = false; while (reader.Read()) { if (reader.IsStartElement()) // opening tag, e.g. <Button { if (tagOpened) { // new line for child element paragraph.Inlines.Add(new LineBreak()); } // indentation paragraph.AddRun(new string(' ', indent * 4), styles.TextStyle); paragraph.AddRun("<", styles.DelimiterStyle); paragraph.AddRun(reader.Name, styles.NameStyle); if (reader.HasAttributes) { // write tag attributes while (reader.MoveToNextAttribute()) { paragraph.AddRun(" " + reader.Name, styles.AttributeStyle); paragraph.AddRun("=", styles.DelimiterStyle); paragraph.AddRun("\"", styles.QuotesStyle); string value; if (reader.Name == "TargetType") // target type fix - should use the Type MarkupExtension { value = "{x:Type " + reader.Value + "}"; } else { value = reader.Value; } paragraph.AddAttributeValue(value, styles); paragraph.AddRun("\"", styles.QuotesStyle); } reader.MoveToElement(); } if (reader.IsEmptyElement) // empty tag, e.g. <Button /> { paragraph.AddRun(" />", styles.DelimiterStyle); paragraph.Inlines.Add(new LineBreak()); tagOpened = false; --indent; } else // non-empty tag, e.g. <Button> { paragraph.AddRun(">", styles.DelimiterStyle); tagOpened = true; } ++indent; } else // closing tag, e.g. </Button> { --indent; // text content of a tag, e.g. the text "Do This" in <Button>Do This</Button> if (reader.NodeType == XmlNodeType.Text) { var content = reader.ReadContentAsString(); if (content.IndexOfAny(new[] { '\r', '\n' }) >= 0 && indent > 0) { // indentation paragraph.AddRun(new string(' ', indent * 4), styles.TextStyle); } paragraph.AddRun(content, styles.TextStyle); } else if (indent > 0) { // indentation paragraph.AddRun(new string(' ', indent * 4), styles.TextStyle); } paragraph.AddRun("</", styles.DelimiterStyle); paragraph.AddRun(reader.Name, styles.NameStyle); paragraph.AddRun(">", styles.DelimiterStyle); paragraph.Inlines.Add(new LineBreak()); tagOpened = false; } } } }
private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var me = (XamlView)d; var target = e.NewValue; var styles = me._styles; var tabs = me._tabs; if (target != null) { var tabsToRemove = new HashSet <string>(tabs.Select(o => o.Name)); foreach (var propertyInfo in target.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { if (!propertyInfo.CanRead || propertyInfo.GetIndexParameters().Length > 0) { continue; } if (AcceptableTypes.All(o => !o.IsAssignableFrom(propertyInfo.PropertyType))) { continue; } var propertyXaml = tabs.FirstOrDefault(o => o.Name == propertyInfo.Name); if (propertyXaml == null) { propertyXaml = new PropertyXaml(propertyInfo.Name); var insertIndex = tabs.Count; for (var i = 0; i < tabs.Count; i++) { if (string.CompareOrdinal(propertyInfo.Name, tabs[i].Name) < 0) { insertIndex = i; break; } } tabs.Insert(insertIndex, propertyXaml); } else { tabsToRemove.Remove(propertyInfo.Name); } var value = propertyInfo.GetValue(target, null); if (value != null) { try { string serializedStyle; using (var stringWriter = new StringWriter()) using (var xmlTextWriter = new XmlTextWriter(stringWriter) { Formatting = Formatting.Indented }) { XamlWriter.Save(value, xmlTextWriter); serializedStyle = stringWriter.ToString(); } var paragraph = new Paragraph { Style = styles.GeneralStyle }; paragraph.FillParagraph(serializedStyle, styles); propertyXaml.Document = new FlowDocument { Blocks = { paragraph } }; } catch (Exception ex) { var message = "[Exception]" + Environment.NewLine + Environment.NewLine + ex; var paragraph = new Paragraph { Style = styles.GeneralStyle }; paragraph.AddRun(message, styles.ErrorStyle); propertyXaml.Document = new FlowDocument { Blocks = { paragraph } }; } } else { var paragraph = new Paragraph { Style = styles.GeneralStyle }; paragraph.AddRun("(NULL)", styles.TextStyle); propertyXaml.Document = new FlowDocument { Blocks = { paragraph } }; } } foreach (var tabName in tabsToRemove) { var tab = tabs.FirstOrDefault(o => o.Name == tabName); if (tab != null) { tabs.Remove(tab); } } } else { tabs.Clear(); } }
/// <summary> /// Creates a FlowDocument from the serialized XAML with simple syntax coloring. /// </summary> /// <param name="success"></param> /// <param name="serializedStyle"></param> /// <returns></returns> private FlowDocument CreateFlowDocument(bool success, string serializedStyle) { var document = new FlowDocument(); if (success) { using (var reader = new XmlTextReader(serializedStyle, XmlNodeType.Document, null)) { var indent = 0; var paragraph = new Paragraph(); while (reader.Read()) { if (reader.IsStartElement()) // opening tag, e.g. <Button { string elementName = reader.Name; // indentation paragraph.AddRun(_textStyle, new string(' ', indent * 4)); paragraph.AddRun(_bracketStyle, "<"); paragraph.AddRun(_elementStyle, elementName); if (reader.HasAttributes) { // write tag attributes while (reader.MoveToNextAttribute()) { paragraph.AddRun(_attributeStyle, " " + reader.Name); paragraph.AddRun(_bracketStyle, "="); paragraph.AddRun(_quotesStyle, "\""); if (reader.Name == "TargetType") // target type fix - should use the Type MarkupExtension { paragraph.AddRun(_textStyle, "{x:Type " + reader.Value + "}"); } else if (reader.Name == "Margin" || reader.Name == "Padding") { paragraph.AddRun(_textStyle, SimplifyThickness(reader.Value)); } else { paragraph.AddRun(_textStyle, reader.Value); } paragraph.AddRun(_quotesStyle, "\""); paragraph.AddLineBreak(); paragraph.AddRun(_textStyle, new string(' ', indent * 4 + elementName.Length + 1)); } paragraph.RemoveLastLineBreak(); reader.MoveToElement(); } if (reader.IsEmptyElement) // empty tag, e.g. <Button /> { paragraph.AddRun(_bracketStyle, " />"); paragraph.AddLineBreak(); --indent; } else // non-empty tag, e.g. <Button> { paragraph.AddRun(_bracketStyle, ">"); paragraph.AddLineBreak(); } ++indent; } else // closing tag, e.g. </Button> { --indent; // indentation paragraph.AddRun(_textStyle, new string(' ', indent * 4)); // text content of a tag, e.g. the text "Do This" in <Button>Do This</Button> if (reader.NodeType == XmlNodeType.Text) { var value = reader.ReadContentAsString(); if (reader.Name == "Thickness") { value = SimplifyThickness(value); } paragraph.AddRun(_textStyle, value); } paragraph.AddRun(_bracketStyle, "</"); paragraph.AddRun(_elementStyle, reader.Name); paragraph.AddRun(_bracketStyle, ">"); paragraph.AddLineBreak(); } } document.Blocks.Add(paragraph); } } else // no style found { document.Blocks.Add(new Paragraph(new Run(serializedStyle)) { TextAlignment = TextAlignment.Left }); } return(document); }