Middle word in Xaml TextBlock is missing, but last word is not

2

I have some text I'm trying to display in xaml, but it looks like it's getting cut off in the middle, but the next word appears. Here's the xaml I have.

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="115" />
    </Grid.ColumnDefinitions>
    <TextBlock TextWrapping="Wrap" HorizontalAlignment="Center" FontFamily="Arial" FontSize="13.33333333">ABCDE IAATA Corp.</TextBlock>
</Grid>                         

Which results in this. Note that the middle word (IAATA) is missing, but the final word (Corp.) is there. Any idea what is going on here? I'd expect that the third word would get wrapped onto a new line, or the second word would appear, with the final word being cutoff, or even both the second and third word getting cut off but not this.

I was able to test this in VS and Kaxaml

Update For some more context, the xaml coming in is generated from else where. I later do some measuring on the xaml elements, which throws a 'FatalExecutionEngineError' exception, which immediately kills the application.

The message is

Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in 
'C:\Projects\TestFailFast\TestFailFast\bin\Debug\TestFailFast.vshost.exe'.

Additional information: The runtime has encountered a fatal error. The address of the error was at 0x583ee28b, on thread 0x2af0. The error code is 0x80131623. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack

and the stacktrace gotten through the event viewer logs is

Application: Services.BackEnd.exe Framework Version: v4.0.30319 

Description: The application requested process termination through System.Environment.FailFast(string message). 
Message: Unrecoverable system error. 
Stack: at 
  System.Environment.FailFast(System.String) at 
  System.Windows.Controls.TextBlock.IsAtCaretUnitBoundary(System.Windows.Documents.ITextPointer, Int32, Int32) at 
  System.Windows.Documents.TextContainer.IsAtCaretUnitBoundary(System.Windows.Documents.TextPointer) at 
  System.Windows.Documents.TextPointer.System.Windows.Documents.ITextPointer.get_IsAtCaretUnitBoundary() at System.Windows.Documents.TextPointerBase.IsAtCaretUnitBoundary(System.Windows.Documents.ITextPointer) at System.Windows.Documents.TextPointerBase.MoveToNextInsertionPosition(System.Windows.Documents.ITextPointer, System.Windows.Documents.LogicalDirection) at 
  System.Windows.Documents.TextPointer.System.Windows.Documents.ITextPointer.GetNextInsertionPosition(System.Windows.Documents.LogicalDirection) 
...

This is only exposed if I have the above xaml wrapped in a FixedDocument like

<FixedDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<PageContent>
    <FixedPage>
        <Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="115" />
            </Grid.ColumnDefinitions>
            <TextBlock Text="ABCDE IAATA Corp." FontFamily="Arial" FontSize="13.333333" TextWrapping="Wrap" HorizontalAlignment="Center"/>
        </Grid>
    </FixedPage>
</PageContent>
</FixedDocument>

I have a sample reproducer here

class Program {
    [STAThread]
    static void Main(string[] args) {
        var fixedPageXaml = @"<FixedDocument xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">
<PageContent>
    <FixedPage>
        <Grid xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width=""115"" />
            </Grid.ColumnDefinitions>
            <TextBlock Text=""ABCDE IAATA Corp."" FontFamily=""Arial"" FontSize=""13.333333"" TextWrapping=""Wrap"" HorizontalAlignment=""Center""/>
        </Grid>
    </FixedPage>
</PageContent>
</FixedDocument>";

        //Search through all xaml elements untill the TextBlock is found
        var textBlock = FindTextBlock(XamlReader.Parse(fixedPageXaml));
        var inline = textBlock.Inlines.FirstInline;

        //Get a TextPointer to the end of a line that is specified relative to the current text pointer 
        // Add 1 to get the beginning of the line following the one count is requesting
        var nextLineStart = inline.ElementStart.GetLineStartPosition(0 + 1); 

        if (nextLineStart != null) {
            //Get the insertion position at the end of the document
            //CRASH!
            var nextPos =  nextLineStart.GetNextInsertionPosition(LogicalDirection.Backward);
        }


        Console.WriteLine("Done");
        Console.Read();
    }

    private static TextBlock FindTextBlock(object root) {
        var fe = root;
        while (fe.GetType() != typeof(TextBlock)) {
            if (fe is FixedDocument) {
                foreach (var p in ((FixedDocument)fe).Pages) {
                    var ret = FindTextBlock(p);
                    if (ret != null) {
                        return ret;
                    }
                }
            } else if (fe is FixedPage) {
                foreach (UIElement c in ((FixedPage)fe).Children) {
                    var ret = FindTextBlock(c);
                    if (ret != null) {
                        return ret;
                    }
                }
            } else if (fe is PageContent) {
                fe = ((PageContent)fe).Child;
            } else if (fe is Grid) {
                foreach (UIElement c in ((Grid)fe).Children) {
                    var ret = FindTextBlock(c);
                    if (ret != null) {
                        return ret;
                    }
                }
            }
        }
        if (fe.GetType() == typeof(TextBlock)) {
            return fe as TextBlock;
        } else {
            return null;
        }
    }
}

This was tested in .net version 4.6.2

c#
wpf
xaml
asked on Stack Overflow Oct 25, 2017 by psadauskas • edited Oct 26, 2017 by psadauskas

1 Answer

3

If you want your textblock to have the same width as the parent, don't set HorizontalAlignment to Left. As a grid child, it'll default to Stretch, which is what you want. Set TextAlignment on the TextBlock to align the text, if desired.

I wonder if this might not be a funny corner case for the arithmetic in the wrapping algorithm, where the "missing" text is just placed out of sight: If I dial FontSize down to 13.256 (but not 13.257), it wraps properly. If I dial it up to 13.341 (but not 13.3405), it wraps properly.


User contributions licensed under CC BY-SA 3.0