Reputation: 3777
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
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):
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
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
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.
Upvotes: 1