47

Is it possible to display the text in a TextBlock vertically so that all letters are stacked upon each other (not rotated with LayoutTransform)?

MarioH
  • 1,165
  • 2
  • 9
  • 15

16 Answers16

80

Nobody has yet mentioned the obvious and trivial way to stack the letters of an arbitrary string vertically (without rotating them) using pure XAML:

<ItemsControl
  ItemsSource="Text goes here, or you could use a binding to a string" />

This simply lays out the text vertically by recognizing the fact that the string is an IEnumerable and so ItemsControl can treat each character in the string as a separate item. The default panel for ItemsControl is a StackPanel, so the characters are laid out vertically.

Note: For precise control over horizontal positioning, vertical spacing, etc, the ItemContainerStyle and ItemTemplate properties can be set on the ItemsControl.

H.B.
  • 166,899
  • 29
  • 327
  • 400
Ray Burns
  • 62,163
  • 12
  • 140
  • 141
28

Just in case anybody still comes across this post... here is a simple 100% xaml solution.

    <TabControl TabStripPlacement="Left">
        <TabItem Header="Tab 1">
            <TabItem.LayoutTransform>
                <RotateTransform Angle="-90"></RotateTransform>      
            </TabItem.LayoutTransform>
            <TextBlock> Some Text for tab 1</TextBlock>
        </TabItem>
        <TabItem Header="Tab 2">
            <TabItem.LayoutTransform>
                <RotateTransform Angle="-90"></RotateTransform>
            </TabItem.LayoutTransform>
            <TextBlock> Some Text for tab 2</TextBlock>
        </TabItem>
    </TabControl>
esko22
  • 389
  • 3
  • 4
19

I don't think there is a straighforward of doing this withought changing the way the system inherently laysout text. The easiest solution would be to change the width of the textblock and supply a few extra properties like this:

<TextBlock TextAlignment="Center" FontSize="14" FontWeight="Bold" Width="10" TextWrapping="Wrap">THIS IS A TEST</TextBlock>

This is hacky, but it does work.

Micah
  • 111,873
  • 86
  • 233
  • 325
18

Just use a simple LayoutTransform..

<Label Grid.Column="0" Content="Your Text Here" HorizontalContentAlignment="Center">
  <Label.LayoutTransform>
    <TransformGroup>
        <RotateTransform Angle="90" />
        <ScaleTransform ScaleX="-1" ScaleY="-1"/>
    </TransformGroup>
  </Label.LayoutTransform>
</Label>
lunatix
  • 817
  • 10
  • 25
  • Thanks for the answer. Really it is the simply and best result because it rotate the text too, it is the most natural way to read the text. – Álvaro García Mar 17 '23 at 10:03
4

It's doable:

Your TextBlock's TextAlignment property should be set to Center:

<TextBlock Name="textBlock1" TextAlignment="Center" Text="Stacked!" />

Then add NewLines between every character:

textBlock1.Text =
    String.Join(
        Environment.NewLine,
        textBlock1.Text.Select(c => new String(c, 1)).ToArray());

(Uses System.Linq to create an array of strings from the individual characters in the original string. I'm sure there are other ways of doing that...)

Christoffer Lette
  • 14,346
  • 7
  • 50
  • 58
3

Below XAML code changes the angle of text displayed in a textblock.

<TextBlock Height="14"
        x:Name="TextBlock1"
        Text="Vertical Bottom to Up" Margin="73,0,115,0" RenderTransformOrigin="0.5,0.5" >
        <TextBlock.RenderTransform>
            <TransformGroup>
                <ScaleTransform/>
                <SkewTransform/>
                <RotateTransform Angle="-90"/>
                <TranslateTransform/>
            </TransformGroup>
        </TextBlock.RenderTransform>
 </TextBlock>
Venkat
  • 1,105
  • 1
  • 8
  • 12
2

the accepted answer suggested by Ray Burns does not work for me on .net 4.0. Here is how I did it:

pull in the mscorlib

xmlns:s="clr-namespace:System;assembly=mscorlib"

put in your usercontrol/window/page resources

<s:String x:Key="SortString">Sort</s:String>

and use it like this

<ItemsControl ItemsSource="{Binding Source={StaticResource SortString}}" Margin="5,-1,0,0"   />    

hope it helps!

TWood
  • 2,563
  • 8
  • 36
  • 58
1

This code allows to have vertical text stacking and horizontal centered letters.

<ItemsControl Grid.Row="1"
              Grid.Column="0"
              ItemsSource="YOUR TEXT HERE"
              HorizontalAlignment="Center"
              VerticalAlignment="Center">

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}"
                   HorizontalAlignment="Center"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

</ItemsControl>
Ugo Robain
  • 3,014
  • 1
  • 14
  • 15
1

create a stackpanel with a bunch ot textblocks that take one char

1

make the text container's max width to allow for one char only and wrap the text:

<TextBlock TextWrapping="Wrap" MaxWidth="8" TextAlignment="Center" Text="stack" />
denis morozov
  • 6,236
  • 3
  • 30
  • 45
  • Despite this being hacky it still seemed so much less effort than the alternatives so I gave it a try, but it has a problem. If you have text with a lower case i in it then because that is quite narrow it might be able to fit the i and the letter next to within the max width of 8. This happens for me with the text "Y axis" where it can fit the i and s on the same line. Changing the maxwidth to 7 then doesn't fit a "W" so in essence this is flawed. – Alan Macdonald Jan 18 '12 at 13:27
1

Make an image and fill the block with the image, use photoshop or something designed to manipulate text instead of fiddling in code ?

mashU2BITs
  • 19
  • 1
0
<linebreak/> can be used to show data in two lines
0

Here's a way to insert a '\n' after every character in the text of the TextBlock, that way making it display vertically:

<TextBlock x:Name="VertTextBlock" Text="Vertical Text" Loaded="VertTextBlock_Loaded"></TextBlock>

Then, in the Loaded event handler, you say:

TextBlock tb = sender as TextBlock;
StringBuilder sb = new StringBuilder(tb.Text);
int len = tb.Text.Length * 2;

for (int i = 1; i < len; i += 2)
{
    sb.Insert(i, '\n');
}

tb.Text = sb.ToString();

That solution was proposed by Lette, but I believe my implementation incurs less overhead.

Boyan
  • 3,645
  • 3
  • 22
  • 14
0

You could also use the "RUN" binding

In the App.xaml file use something like this:

<Application x:Class="Some.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:commands="clr-namespace:Deridiam.Helper.Commands"
         xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
         ShutdownMode="OnMainWindowClose"
         StartupUri="Views/MainWindow.xaml">
<Application.Resources>

    <commands:HorizontalToVertical x:Key="HorizontalToVertical_Command"></commands:HorizontalToVertical>

    <ControlTemplate x:Key="VerticalCell" TargetType="ContentControl">
            <TextBlock Text="{TemplateBinding Content}" Foreground="Black"
                    TextAlignment="Center" FontWeight="Bold" VerticalAlignment="Center"
                    TextWrapping="Wrap" Margin="0" FontSize="10">  
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Loaded">
                        <i:InvokeCommandAction Command="{Binding ConvertToVerticalCmd, Source={StaticResource HorizontalToVertical_Command}}" 
                                               CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TextBlock}}}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </TextBlock>
    </ControlTemplate>

</Application.Resources>

Create the command class binded to the textblock using i:Interaction.Triggers on the Loaded event in the app.xaml example

namespace Deridiam.Helper.Commands
{
public class HorizontalToVertical
{
    private ICommand _convertToVerticalCommand;

    public ICommand ConvertToVerticalCmd =>
        _convertToVerticalCommand ?? (_convertToVerticalCommand = new RelayCommand(
                x =>
                {
                    var tBlock = x as TextBlock;
                    var horizontalText = tBlock.Text;
                    tBlock.Text = "";

                    horizontalText.Select(c => c).ToList().ForEach(c =>
                    {
                        if (c.ToString() == " ")
                        {
                            tBlock.Inlines.Add("\n");
                            //tBlock.Inlines.Add("\n");
                        }

                        else
                        {
                            tBlock.Inlines.Add((new Run(c.ToString())));
                            tBlock.Inlines.Add(new LineBreak());
                        }


                    });
                }));
}
}

Finally in the .xaml file where you want the vertical text to be shown

<ContentControl Width="15" Content="Vertical Text" Template="{StaticResource VerticalCell}">
</ContentControl>

Will result in:

V
e
r
t
i
c
a
l

T
e
x
t

0

none of the above solutions solved my problem (some come close), so I'm here to post my solution and maybe help someone. The accepted solution helped me, but the text is not aligned to the center.

<ItemsControl ItemsSource="{Binding SomeStringProperty, FallbackValue=Group 1}" Margin="5"
          TextElement.FontSize="16" 
          TextElement.FontWeight="Bold" 
          TextBlock.TextAlignment="Center"
          HorizontalAlignment="Center" 
          VerticalAlignment="Center" >
<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <WrapPanel Orientation="Vertical" />
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
    <DataTemplate  >
        <TextBlock Text="{Binding }" HorizontalAlignment="Center"  />
    </DataTemplate>
</ItemsControl.ItemTemplate>
Celso Lívero
  • 716
  • 2
  • 14
  • 18
-2

I will offer a solution based on the converter:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;

namespace Converters
{
    [ValueConversion(typeof(object), typeof(string))]
    public class InsertLineBreakConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (parameter != null)
                value = parameter;

            if (value == null)
                return null;

            if (!(value is string str))
                str = value.ToString();

            return string.Join(Environment.NewLine, (IEnumerable<char>) str);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        public static InsertLineBreakConverter Instance { get; } = new InsertLineBreakConverter();
    }

    public class InsertLineBreakConverterExtension : MarkupExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
            => InsertLineBreakConverter.Instance;
    }
}

Usage examples:

   <TextBlock Text="{Binding Property, Converter={cnvs:InsertLineBreakConverter}}"/>   
   <TextBlock Text="{Binding Converter={cnvs:InsertLineBreakConverter}, ConverterParameter='Some Text'}"/>
EldHasp
  • 6,079
  • 2
  • 9
  • 24