none
PropertyElements and xml:space="preserve" is invalid. Why?

    Question

  • Hello All,

    Consider the following:

    <TextBlock>
        <TextBlock.Text xml:space="preserve">
            This
            is
            on
            many
            lines
        </TextBlock.Text>
    </TextBlock> 

    This should be perfectly valid XML and from my reading of the XAML documentation, it should be perfectly valid XAML.  The intention being to preserve the whitespace in the content of the TextBlock.Text property element.  The result, however, is an XamlParseException: "Cannot set properties on property elements."

    1. Xaml Syntax Terminology here.
    2. Xaml White Space Handling doco here.

    (1) talks about "Object Elements" and "Property Elements" - "Element" is not defined and it is assumed that "Element" refers to both Object and Property Elements.  I take the term Element to be analogous with the XML Elements.

    (2) states "xml:space="preserve": Specify this attribute at the level of the element where whitespace preservation is desired".

    It is not desireable to propmote the xml:space element to the Object Element level as you lose the ability to specify whitesapce handling on individual properties of an object.  For example:

    <z:MyClass>
        <z:MyClass.String1 xml:space="preserve">
            With whitespace preservation
        </z:MyClass.String1>
        <z:MyClass.String2>
            Without whitespace preservation
        </z:MyClass.String2>

    <z:MyClass>

    Assume that String2 is the default content property of MyClass, then the following is impossible

    <z:MyClass>
        <z:MyClass.String1 xml:space="preserve">
            With whitespace preservation
        </z:MyClass.String1>

        Without whitespace preservation
    <z:MyClass>

    Now, is this by design, or is it an error in the XAML parser?


    Cheers,

    Dan

    Friday, August 29, 2008 1:59 AM

Answers

  • Hello, came across your problem and tried it out for myself. I cannot comment on whether it's a bug or not but it's certainly a limitation with the second case, the custom class.

    It's not perfect but a workaround would be to create a custom MarkupExtension. This lets you specify some whitespace.


       <local:MyClass>

            <local:MyClass.String1>

                <local:PreserveSpace Value="    Hello World"/>

            </local:MyClass.String1>

            <local:MyClass.String2>

                Goodbye World

            </local:MyClass.String2>

        </local:MyClass>




        public class PreserveSpaceExtension : MarkupExtension

        {

            public string Value { get; set; }

     

            public PreserveSpaceExtension()

            {     }

     

            public PreserveSpaceExtension(string value)

            {

                this.Value = value;

            }

     

            public override object ProvideValue(IServiceProvider serviceProvider)

            {

                return this.Value;

            }

        }


    www.dsmyth.net | www.dsmyth.net/wiki
    • Marked as answer by Marco Zhou Tuesday, September 2, 2008 9:34 AM
    Monday, September 1, 2008 11:02 AM
  • Hello Derek,

    Thanks for the suggestion.  I am interested in the multi-line string case, which rules out any sort of attribute usage.  The following is a better general solution for when a multiline string is needed (where xmlns:system maps to the System clr namespace):

    <z:MyClass>
       <z:MyClass.String1>
           <system:String xml:space="preserve">
               With whitespace preservation,
               including line breaks and indentation.
           </system:String>
       </z:MyClass.String1>
       Without whitespace preservation
    <z:MyClass>

    Couple this with CDATA sections and you're well on your way to embedding arbitrary text in XAML element's content.

    I find it very disappointing that MS clearly states that, "XAML files are XML files that generally have the .xaml extension." and yet the fundamental parts of XML parsing are broken in the XAML.


    Cheers,

    Dan

    • Marked as answer by Marco Zhou Tuesday, September 2, 2008 9:34 AM
    Tuesday, September 2, 2008 1:14 AM

All replies

  • It appears that I am not alone with this issue:

    http://blogs.msdn.com/johngossman/archive/2005/05/13/417406.aspx

    The author of the blog states that, "I reported the bug...but now I'm kinda stuck".  That was over three years ago.

    Can some one at Microsoft tell me if this behavior is by design, or is it a bug?  The answer to that question will have a large impact on my design.


    Cheers,

    Dan

    Monday, September 1, 2008 3:35 AM
  • Hello, came across your problem and tried it out for myself. I cannot comment on whether it's a bug or not but it's certainly a limitation with the second case, the custom class.

    It's not perfect but a workaround would be to create a custom MarkupExtension. This lets you specify some whitespace.


       <local:MyClass>

            <local:MyClass.String1>

                <local:PreserveSpace Value="    Hello World"/>

            </local:MyClass.String1>

            <local:MyClass.String2>

                Goodbye World

            </local:MyClass.String2>

        </local:MyClass>




        public class PreserveSpaceExtension : MarkupExtension

        {

            public string Value { get; set; }

     

            public PreserveSpaceExtension()

            {     }

     

            public PreserveSpaceExtension(string value)

            {

                this.Value = value;

            }

     

            public override object ProvideValue(IServiceProvider serviceProvider)

            {

                return this.Value;

            }

        }


    www.dsmyth.net | www.dsmyth.net/wiki
    • Marked as answer by Marco Zhou Tuesday, September 2, 2008 9:34 AM
    Monday, September 1, 2008 11:02 AM
  • Hello Derek,

    Thanks for the suggestion.  I am interested in the multi-line string case, which rules out any sort of attribute usage.  The following is a better general solution for when a multiline string is needed (where xmlns:system maps to the System clr namespace):

    <z:MyClass>
       <z:MyClass.String1>
           <system:String xml:space="preserve">
               With whitespace preservation,
               including line breaks and indentation.
           </system:String>
       </z:MyClass.String1>
       Without whitespace preservation
    <z:MyClass>

    Couple this with CDATA sections and you're well on your way to embedding arbitrary text in XAML element's content.

    I find it very disappointing that MS clearly states that, "XAML files are XML files that generally have the .xaml extension." and yet the fundamental parts of XML parsing are broken in the XAML.


    Cheers,

    Dan

    • Marked as answer by Marco Zhou Tuesday, September 2, 2008 9:34 AM
    Tuesday, September 2, 2008 1:14 AM
  • Hi Dan,

    Thanks for posting that better approach, it's a far better approach. I've fairly new to WPF and using the forums to learn about WPF as it's applied in real world project (instead of the ideal, it always works, world of books).

    This topic and fix will be useful to know in the future, so thanks for that Dan.

    I understand your disappointment, with this example, you'd have thought 

        <local:MyClass>

            <local:MyClass.String1 xml:space="preserve">

                    Hello

                    World

            </local:MyClass.String1>

        </local:MyClass>


    ... it would have worked.... it's XML and there is very little difference in the above and the fix. Makes you wonder what other markup is out there waiting to catch the unexpected out.




    www.dsmyth.net | www.dsmyth.net/wiki
    Tuesday, September 2, 2008 9:25 AM
  • <Page x:Class="WPFTest.Page1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Page1">
        <Grid>
            <TextBlock xml:space="preserve">
                <TextBlock.Text>
                sadfafewq fqewf
                asdfa
                as
                adsf
                </TextBlock.Text>
            </TextBlock>
        </Grid>
    </Page>

    or

            <TextBlock xml:space="preserve">
                sadfafewq fqewf
                asdfa
                as
                adsf
            </TextBlock>


    Work exactly as it should. Removing xml:space="preserve" will resolve in single line text display.
    Tried with VS 2008 (no SP1) and XAMLPad 3.0

    Bigsby, Lisboa, Portugal
    Tuesday, September 2, 2008 9:37 AM
  • Hello Bigsby,

    Thank you for your comments, but you have missed the point of the post.  You should note that although the observed behaviour of the TextBlock was to display a single line of text regardless of the XML directive to preserve whitespace, under the hood the Xaml parser did not "work exactly as it should".  To avoid confusion, I should have used a case that made the problem obvious in its on-screen display.  Please redo your experiments with a TextBox rather than a text block and let me know your findings.

    <TextBox Height="100">
    Some
    Multiline
    Sting
    Where
    All
    Whitespace
    Is
    Important
       Including
       Indentation
    </TextBox>

    The above (correctly) will not work preserve whitespace, while the following (correctly) will:

    <TextBox Height="100" xml:space="preserve">
    Some
    Multiline
    Sting
    Where
    All
    Whitespace
    Is
    Important
       Including
       Indentation
    </TextBox>


    The following should be equivalent to that above, but is broken:

    <TextBox Height="100">
        <TextBox.Text xml:space="preserve">
    Some
    Multiline
    Sting
    Where
    All
    Whitespace
    Is
    Important
       Including
       Indentation
        </TextBox.Text>
    </TextBox>


    So, if TextBox.Text was not the default context of the TextBox, you'd be stuffed if you needs to preserve white space.  Luckily we have a not-too-intrusive workaround that requires no code behind and does not promote the xml:space to a higher scope than required:

    <TextBox Height="100">
        <TextBox.Text>
            <system:String xml:space="preserve">
     
    Some
    Multiline
    Sting
    Where
    All
    Whitespace
    Is
    Important
       Including
       Indentation
            </system:String>
        </TextBox.Text>
    </TextBox>


    Now, just because the workaround is not-too-intrusive, that's no excuse for the Xaml parser to be non-compliant with the XML spec.  I personally hate that this workaround is sprayed all through my Xaml rather than localised to a single place.

    Hey Derek - I was pretty chuffed when I thought of simply sticking in a string like that.


    Cheers,

    Dan

    Thursday, September 4, 2008 1:35 AM

  • I have written this up in a little more detail on my blog:

    http://www.thinkbottomup.com.au/site/node/10

    I hope it saves some people from banging their heads on a wall for as long as I did!


    Cheers,

    Dan


    Saturday, September 13, 2008 8:32 AM