为什么恐惧?因为它不工作,我猜想,你的期望.下表A应该生产
BARN
(每个角色都有花式的颜色),而是产生:
B A R N
展览A
<TextBlock FontFamily="Comic Sans MS" FontSize="88"> <Run Foreground="#A200FF">B</Run> <Run Foreground="#FF0000">A</Run> <Run Foreground="#FFC000">R</Run> <Run Foreground="#FFFF00">N</Run> </TextBlock>
然而,产生理想结果的是:
展览B
<TextBlock FontFamily="Comic Sans MS" FontSize="88"> <Run Foreground="#A200FF">B</Run><Run Foreground="#FF0000">A</Run><Run Foreground="#FFC000">R</Run><Run Foreground="#FFFF00">N</Run> </TextBlock>
笨,呃无论如何,这是记录在@ XAML Processing Differences Between Silverlight 3 and Silverlight 4在Whitespace处理它说:
Silverlight 3 treats whitespace more
literally in a wider range,including
some cases where CLRF is considered
significant. This sometimes led to
file-format XAML with omitted CRLF in
order to avoid unwanted whitespace in
the presentation,but which was not
human-readable in editing
environments. Silverlight 4 uses a
more intuitive significant-whitespace
model that is similar to WPF. This
model collapses file-formatting
whitespace in most cases,with
exception of certain CLR-attributed
containers that treat all whitespace
as significant. This whitespace model
gives editing environments greater
freedom to introduce whitespace that
can improve XAML code formatting.
Also,Silverlight 4 has text elements
that permit even greater control over
whitespace presentation issues.
很棒,但是我没有使用SL4,因为我以编程方式创建了WP7应用程序.是的,我的XAML生成.使用XML文字.然后发送到一个字符串.喜欢这个:
Dim r1 As XElement = <Run Foreground="#A200FF">B</Run> Dim r2 As XElement = <Run Foreground="#FF0000">A</Run> Dim r3 As XElement = <Run Foreground="#FFC000">R</Run> Dim r4 As XElement = <Run Foreground="#FFFF00">N</Run> Dim tb = <TextBlock FontFamily="Comic Sans MS" FontSize="88"> <%= r1 %><%= r2 %><%= r3 %><%= r4 %> </TextBlock> Dim result = tb.ToString
毕竟,这是我的问题:我如何生产展览B而不是展览A.该文本块将成为XAML页面中更多元素的一部分,所以.ToString部分在这个位置不是很准确 – 当用户控制页面的所有XAML被踢出来时都会发生.
编辑(2011年5月6日):有一点进步和赏金
我已经做了一些进展如下,但我正在运行一个精神障碍在这里如何完成一个不寻常的分裂和处理XML输出一个字符串.拿这个新例子:
<Canvas> <Grid> <TextBlock> <Run Text="r"/> <Run Text="u"/> <Run Text="n"/> </TextBlock> <TextBlock> <Run Text="far a"/> <Run Text="way"/> <Run Text=" from me"/> </TextBlock> </Grid> <Grid> <TextBlock> <Run Text="I"/> <Run Text=" "/> <Run Text="want"/> <LineBreak/> </TextBlock> <TextBlock> <LineBreak/> <Run Text="...thi"/> <Run Text="s to"/> <LineBreak/> <Run Text=" work"/> </TextBlock> </Grid> </Canvas>
我想要输出字符串:
<Canvas> <Grid> <TextBlock> <Run Text="r"/><Run Text="u"/><Run Text="n"/> </TextBlock> <TextBlock> <Run Text="far a"/><Run Text="way"/><Run Text=" from me"/> </TextBlock> </Grid> <Grid> <TextBlock> <Run Text="I"/><Run Text=" "/><Run Text="want"/> <LineBreak/> </TextBlock> <TextBlock> <LineBreak/> <Run Text="...thi"/><Run Text="s to"/> <LineBreak/> <Run Text=" work"/> </TextBlock> </Grid> </Canvas>
我一直在研究基于Eric White’s post的XMLWriter和XMLWriterSettings,它似乎是一个很好的开始(不包括潜在的< lineBreak /> s,这也阻碍了我).喜欢这个:
Sub Main() Dim myXML As XElement = <Canvas> <Grid> <TextBlock> <Run Text="r"/> <Run Text="u"/> <Run Text="n"/> </TextBlock> <TextBlock> <Run Text="far a"/> <Run Text="way"/> <Run Text=" from me"/> </TextBlock> </Grid> </Canvas> Console.Write(ToXMLString(myXML)) Console.ReadLine() End Sub Public Function ToXMLString(xml As XElement) As String Dim tb As XElement = xml.Elements.<TextBlock>.FirstOrDefault Dim xmlWriterSettings As New XmlWriterSettings XmlWriterSettings.NewLineHandling = NewLineHandling.None XmlWriterSettings.OmitXmlDeclaration = True Dim sb As New StringBuilder Using xmlwriter As XmlWriter = xmlwriter.Create(sb,XmlWriterSettings) tb.WriteTo(xmlwriter) End Using Return sb.ToString End Function
但是,我有一个巨大的问题进一步,找出如何解析,以产生所需的输出.
递归函数最初使用’outer’XmlWriter,写入缩进的XML,直到它看到TextBlock元素.当它遇到TextBlock元素时,它创建’inner’XmlWriter对象,将TextBlock元素的子元素写入它.它还将空格写入“内部”XmlWriter.
当写入TextBlock元素的“内部”XmlWriter对象完成时,写入器写入的文本将使用WriteRaw方法写入“外部”XmlWriter.
这种方法的优点是没有对XML进行后处理.后处理XML是非常困难的,并确保您已正确处理所有案例,包括CData节点中的任意文本等.所有XML仅使用XmlWriter类编写,从而确保始终写入有效的XML .唯一的例外是使用WriteRaw方法编写的特制白色空间,可实现所需的缩进行为.
一个关键点是“内部”XmlWriter对象的一致性级别设置为ConformanceLevel.Fragment,因为“内部”XmlWriter需要编写没有根元素的XML.
为了实现Run元素所需的格式化(即相邻的Run元素在它们之间没有无关紧要的空格),代码使用GroupAdjacent扩展方法.前段时间,我在the GroupAdjacent extension method for VB写了一篇博文.
<Canvas> <Grid> <TextBlock> <Run Text="r" /><Run Text="u" /><Run Text="n" /> </TextBlock> <TextBlock> <Run Text="far a" /><Run Text="way" /><Run Text=" from me" /> </TextBlock> </Grid> <Grid> <TextBlock> <Run Text="I" /><Run Text=" " /><Run Text="want" /> <LineBreak /> </TextBlock> <TextBlock> <LineBreak /> <Run Text="...thi" /><Run Text="s to" /> <LineBreak /> <Run Text=" work" /> </TextBlock> </Grid> </Canvas>
以下是VB.NET示例程序的完整列表.另外,我写了一篇博客文章Custom Formatting of XML using LINQ to XML,它提供了等效的C#代码.
`
Imports System.Text Imports System.Xml Public Class GroupOfAdjacent(Of TElement,TKey) Implements IEnumerable(Of TElement) Private _key As TKey Private _groupList As List(Of TElement) Public Property GroupList() As List(Of TElement) Get Return _groupList End Get Set(ByVal value As List(Of TElement)) _groupList = value End Set End Property Public ReadOnly Property Key() As TKey Get Return _key End Get End Property Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of TElement) _ Implements System.Collections.Generic.IEnumerable(Of TElement).GetEnumerator Return _groupList.GetEnumerator End Function Public Function GetEnumerator1() As System.Collections.IEnumerator _ Implements System.Collections.IEnumerable.GetEnumerator Return _groupList.GetEnumerator End Function Public Sub New(ByVal key As TKey) _key = key _groupList = New List(Of TElement) End Sub End Class Module Module1 <System.Runtime.CompilerServices.Extension()> _ Public Function GroupAdjacent(Of TElement,TKey)(ByVal source As IEnumerable(Of TElement),_ ByVal keySelector As Func(Of TElement,TKey)) As List(Of GroupOfAdjacent(Of TElement,TKey)) Dim lastKey As TKey = Nothing Dim currentGroup As GroupOfAdjacent(Of TElement,TKey) = Nothing Dim allGroups As List(Of GroupOfAdjacent(Of TElement,TKey)) = New List(Of GroupOfAdjacent(Of TElement,TKey))() For Each item In source Dim thisKey As TKey = keySelector(item) If lastKey IsNot Nothing And Not thisKey.Equals(lastKey) Then allGroups.Add(currentGroup) End If If Not thisKey.Equals(lastKey) Then currentGroup = New GroupOfAdjacent(Of TElement,TKey)(keySelector(item)) End If currentGroup.GroupList.Add(item) lastKey = thisKey Next If lastKey IsNot Nothing Then allGroups.Add(currentGroup) End If Return allGroups End Function Public Sub WriteStartElement(ByVal writer As XmlWriter,ByVal e As XElement) Dim ns As XNamespace = e.Name.Namespace writer.WriteStartElement(e.GetPrefixOfNamespace(ns),_ e.Name.LocalName,ns.NamespaceName) For Each a In e.Attributes ns = a.Name.Namespace Dim localName As String = a.Name.LocalName Dim namespaceName As String = ns.NamespaceName writer.WriteAttributeString( _ e.GetPrefixOfNamespace(ns),_ localName,_ IIf(namespaceName.Length = 0 And localName = "xmlns",_ XNamespace.Xmlns.NamespaceName,namespaceName),a.Value) Next End Sub Public Sub WriteElement(ByVal writer As XmlWriter,ByVal e As XElement) If (e.Name = "TextBlock") Then WriteStartElement(writer,e) writer.WriteRaw(Environment.NewLine) ' Create an XML writer that outputs no insignificant white space so that we can ' write to it and explicitly control white space. Dim settings As XmlWriterSettings = New XmlWriterSettings() settings.Indent = False settings.OmitXmlDeclaration = True settings.ConformanceLevel = ConformanceLevel.Fragment Dim sb As StringBuilder = New StringBuilder() Using newXmlWriter As XmlWriter = XmlWriter.Create(sb,settings) ' Group adjacent runs so that they can be output with no whitespace between them Dim groupedRuns = e.Nodes().GroupAdjacent( _ Function(n) As Boolean? If TypeOf n Is XElement Then Dim element As XElement = n If element.Name = "Run" Then Return True End If Return False End If Return False End Function) For Each g In groupedRuns If g.Key = True Then ' Write white space so that the line of Run elements is properly indented. newXmlWriter.WriteRaw("".PadRight((e.Ancestors().Count() + 1) * 2)) For Each run In g run.WriteTo(newXmlWriter) Next newXmlWriter.WriteRaw(Environment.NewLine) Else For Each g2 In g ' Write some white space so that each child element is properly indented. newXmlWriter.WriteRaw("".PadRight((e.Ancestors().Count() + 1) * 2)) g2.WriteTo(newXmlWriter) newXmlWriter.WriteRaw(Environment.NewLine) Next End If Next End Using writer.WriteRaw(sb.ToString()) writer.WriteRaw("".PadRight(e.Ancestors().Count() * 2)) writer.WriteEndElement() Else WriteStartElement(writer,e) For Each n In e.Nodes If TypeOf n Is XElement Then Dim element = n WriteElement(writer,element) Continue For End If n.WriteTo(writer) Next writer.WriteEndElement() End If End Sub Function ToStringWithCustomWhiteSpace(ByVal element As XElement) As String ' Create XmlWriter that indents. Dim settings As XmlWriterSettings = New XmlWriterSettings() settings.Indent = True settings.OmitXmlDeclaration = True Dim sb As StringBuilder = New StringBuilder() Using xmlWriter As XmlWriter = xmlWriter.Create(sb,settings) WriteElement(xmlWriter,element) End Using Return sb.ToString() End Function Sub Main() Dim myXML As XElement = _ <Canvas> <Grid> <TextBlock> <Run Text='r'/> <Run Text='u'/> <Run Text='n'/> </TextBlock> <TextBlock> <Run Text='far a'/> <Run Text='way'/> <Run Text=' from me'/> </TextBlock> </Grid> <Grid> <TextBlock> <Run Text='I'/> <Run Text=' '/> <Run Text='want'/> <LineBreak/> </TextBlock> <TextBlock> <LineBreak/> <Run Text='...thi'/> <Run Text='s to'/> <LineBreak/> <Run Text=' work'/> </TextBlock> </Grid> </Canvas> Console.Write(ToStringWithCustomWhiteSpace(myXML)) Console.ReadLine() End Sub End Module
`