MarioH
MarioH

Reputation: 1157

Vertical Text in Wpf TextBlock

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

Upvotes: 48

Views: 70983

Answers (16)

EldHasp
EldHasp

Reputation: 7908

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'}"/>

Upvotes: -2

Celso L&#237;vero
Celso L&#237;vero

Reputation: 726

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>

Upvotes: 0

Chelaru Alexandru
Chelaru Alexandru

Reputation: 1

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

Upvotes: 0

lunatix
lunatix

Reputation: 807

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>

Upvotes: 18

Ugo Robain
Ugo Robain

Reputation: 3064

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>

Upvotes: 1

mashU2BITs
mashU2BITs

Reputation: 19

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

Upvotes: 1

Ray Burns
Ray Burns

Reputation: 62919

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.

Upvotes: 81

denis morozov
denis morozov

Reputation: 6316

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" />

Upvotes: 1

Venkat
Venkat

Reputation: 1111

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>

Upvotes: 3

TWood
TWood

Reputation: 2583

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!

Upvotes: 2

denis morozov
denis morozov

Reputation: 11

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

Upvotes: 1

Christoffer Lette
Christoffer Lette

Reputation: 14816

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

Upvotes: 4

esko22
esko22

Reputation: 389

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>

Upvotes: 28

Amit
Amit

Reputation:

<linebreak/> can be used to show data in two lines

Upvotes: 0

Boyan
Boyan

Reputation: 3715

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.

Upvotes: 0

Micah
Micah

Reputation: 116090

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.

Upvotes: 20

Related Questions