Vertical Text in Wpf TextBlock
Asked Answered
A

16

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)?

Antimatter answered 8/12, 2008 at 15:34 Comment(0)
C
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.

Castleberry answered 19/1, 2010 at 3:59 Comment(2)
Overcome the "does not convert from string" problem for a fixed string by creating a string resource and binding it to the Items Source: <Expander.Resources><system:String x:Key="Title">Stacked text</system:String></Expander.Resources> <Expander.Header><ItemsControl ItemsSource="{StaticResource Title}"></Expander.Header>Antrorse
can be done inline, without resource: <ItemsControl ItemsSource="{Binding Source='some text'}"/>Excommunication
A
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>
Agenesis answered 19/1, 2010 at 1:5 Comment(0)
B
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.

Bicarbonate answered 8/12, 2008 at 15:59 Comment(0)
D
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>
Direful answered 31/7, 2013 at 12:39 Comment(1)
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.Latonia
M
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...)

Morn answered 8/12, 2008 at 22:32 Comment(0)
D
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>
Dessiedessma answered 15/2, 2011 at 8:48 Comment(0)
A
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!

Arrant answered 13/10, 2010 at 18:25 Comment(0)
O
1

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

Oisin answered 28/9, 2010 at 16:47 Comment(0)
O
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" />
Oisin answered 29/9, 2010 at 16:19 Comment(1)
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.Laurustinus
E
1

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

Embolden answered 21/3, 2012 at 19:48 Comment(0)
D
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>
Decorous answered 8/10, 2012 at 18:19 Comment(0)
P
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.

Provencal answered 9/12, 2008 at 6:4 Comment(0)
R
0
<linebreak/> can be used to show data in two lines
Refraction answered 9/9, 2009 at 5:46 Comment(0)
B
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

Bussey answered 6/4, 2020 at 8:47 Comment(0)
C
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>
Canea answered 28/5, 2021 at 13:18 Comment(0)
K
-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'}"/>
Kinelski answered 23/6, 2021 at 6:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.