Question

Banging my head trying to figure this out. The goal is to create a wrapping TextBox at a given location where the width is set to that of the largest word in the string of text. FormattedText.MinWidth calculates the width of the largest word in the string. But passing that MinWidth to the TextBox causes the TextBox to be slightly too narrow. TextBlock does not have this problem.

Evidentally something is happening deep down inside the TextBox causing this behavior. I can't just add a fixed magic number to the TextBox width because the increase in the width needed to correct the problem will always differ based on the pixel width of the character that was wrapped to the next line. The number of pixels will always differ depending on what that character is, the font, and font size.

If someone has more reputation could you please add FormattedText and MinWidth as a tag? Restrictions won't let me, a stupid first post newbe, do this. I also would like to have added an image which would make this sooo much easier to understand but stupid restrictions (did I say that?) prevent me from doing so.

namespace FormattedTextExample
{
    public partial class FormattedText1 : Window
    {
        string noteText =
                "We hold these truths to be self-evident, that all men are created equal, that they " +
                "are endowed by their Creator with certain unalienable Rights, that among these are " +
                "Life, Liberty and the pursuit of Happiness.--That to secure these rights, Governments " +
                "are instituted..";

        public FormattedText1()
        {
            InitializeComponent();
            myText.Text = noteText;
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            FormattedText ft = new FormattedText(
                textToFormat: noteText,
                culture: CultureInfo.GetCultureInfo("en-us"),
                flowDirection: myText.FlowDirection,
                typeface: new Typeface(myText.FontFamily.ToString()),
                emSize: myText.FontSize,
                foreground: myText.Foreground);
            ft.MaxTextWidth = ft.MinWidth;

            DrawingContext dc = drawDest.Open();
            dc.DrawText(ft, new Point(0, 0));
            dc.Close();
            myDrawingBrush.Drawing = drawDest;

            myText.Width = ft.MinWidth;
        }
    }
}

<Window x:Class="FormattedTextExample.FormattedText1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="FormattedText" Height="500" Width="500">
    <DockPanel>
        <Grid DockPanel.Dock="Top"  ShowGridLines="True">
            <Grid.RowDefinitions>
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Rectangle Grid.Column="0">
                <Rectangle.Fill>
                    <DrawingBrush x:Name="myDrawingBrush" Stretch="None" 
                         AlignmentY="Top" AlignmentX="Left" >
                        <DrawingBrush.Drawing>
                            <DrawingGroup x:Name="drawDest" />
                        </DrawingBrush.Drawing>
                    </DrawingBrush>
                </Rectangle.Fill>
            </Rectangle>
            <StackPanel Grid.Column="1">
                <TextBox x:Name="myText" TextWrapping="Wrap" />
                <!-- Everything works fine if using TextBlock -->
                <!--<TextBlock x:Name="myText" TextWrapping="Wrap" />-->
            </StackPanel>
        </Grid>
    </DockPanel>
</Window>
Was it helpful?

Solution

The reason your textbox needs more space is the way its control template is defined.

This is how the default control template looks like (from MSDN):

    <ControlTemplate TargetType="{x:Type TextBoxBase}">
        <Border Name="Border"
                BorderThickness="1"
                CornerRadius="2"
                Padding="2">
            <Border.Background>
                <SolidColorBrush Color="{DynamicResource ControlLightColor}" />
            </Border.Background>
            <Border.BorderBrush>
                <SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
            </Border.BorderBrush>
            <!-- VisualStateManager code -->
            <ScrollViewer x:Name="PART_ContentHost" Margin="0" />
        </Border>
    </ControlTemplate>

Studying the default control template or defining your own helps determining exactly how much extra space do you need to allocate to your text box.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top