Lews Therin
Lews Therin

Reputation: 3777

How to align string contents text in a listbox?

I'm having a problem aligning string contents in a listbox. Here's a distilled example that demonstrates the problem my app is having:

Basic XAML UI:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="687" Loaded="Window_Loaded">
    <Grid>
        <ListBox x:Name="lstClients" HorizontalAlignment="Left" Height="220" Margin="28,22,0,0" VerticalAlignment="Top" Width="625"/>
    </Grid>
</Window>

Code behind:

Class MainWindow
    Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
        Dim names() As String = {"Cook, Adam", "Renolds, Bridgette", "Smith, Carla", "Doe, Daniel",
                                "Redmond, Ebenezer", "Kelly, Francine"}
        Dim ids() As String = {"123456", "654321", "112345", "274587", "128493", "937401"}
        Dim dob() As String = {"1/2/80", "4/17/88", "8/31/72", "6/11/91", "10/27/81", "3/3/75"}
        Dim phones() As String = {"1234567890", "2536772364", "1537779004", "7586712164", "8548778384", "0987654321"}

        For i As Integer = 0 To 5
            lstClients.Items.Add(FormatClientString(names(i), ids(i), dob(i), phones(i)))
        Next
    End Sub

    Private Function FormatClientString(name As String, id As String, birthDate As String, phone As String)
        Dim clientString As String
        clientString = String.Format("{0, -52} {1, -17} {2, -20} {3}", name, id, birthDate, phone)
        Return clientString
    End Function
End Class

Output: output

And here is what I am actually trying to accomplish (crappy paint editing but basically I just want the columns to align, regardless of the length of the client's name): desiredOutput

From what I read, String.Format should do what I want, but the output is never right. I also tried using String.PadRight for each string (names, ids, dob, and phones) but got the same behavior (misaligned columns).

Am I overlooking something simple?

EDIT: The control in my actual app is not a ListBox. It is an AutoCompleteBox from the WPF Toolkit. I used the ListBox above as an example because it was exhibiting the same behavior formatting the strings and was easier to make a simple example with.

If anyone knows how to add columns to the AutoCompleteBox's dropdown suggestions, that would work too as this is ultimately the goal.

Upvotes: 0

Views: 2720

Answers (2)

Steve
Steve

Reputation: 216363

The problem is caused by the font used by your control. It is a proportional font so you cannot create columns of a certain width using spaces to fill the column because every line has a different length in pixels of the text part.

Setting a fixed width font like Consolas (where every character has the same width in pixels) will fix the problem.

However the fixed width font is not very pleasant to see and a better solution is to use a control that 'knows' what 'multi columns' means. (ListView, DataGrid)

Upvotes: 2

King King
King King

Reputation: 63387

For those who want to show string.Format with proportional fonts, try this XAML (which is just for fun, but may be used in some simple apps which don't require much flexibility in styling). Using this code, we may need to tweak the fixed Width depending on the chosen font:

<ListBox x:Name="lstClients" HorizontalAlignment="Left" Height="220" Margin="28,22,0,0" 
         VerticalAlignment="Top" Width="625" FontFamily="Lucida Calligraphy">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <ItemsControl ItemsSource="{Binding}">                        
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Border Width="20" Margin="0,0,-12,0">
                                <TextBlock Text="{Binding}" TextAlignment="Center"/>
                            </Border>                                
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Horizontal"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </DataTemplate>
        </ListBox.ItemTemplate>
</ListBox>

The idea here is each string is an array of characters. So we define an ItemTemplate foreach data item (a string). The template should be an ItemsControl to show a list of characters in a custom ItemsPanelTemplate to stack those characters horizontally (to join in a readable text). Because each character is a Border having fixed width, it can be used with any font with appropriate Width set for Border (and its Margin). For wrapping text, we may need to play with WrapPanel instead. But anyway it's some kind of funny trick and should not be used in important business apps.

enter image description here

Upvotes: 1

Related Questions