string.Format with dynamic length left aligned text in C#



This post is about dynamic text alignment with C#.

Scenario: I wanted to implement a dropdownlist with list items left aligned based on a string format. This is the initial appearance of the dropdown with no text alignment applied:

DropDownList with Text not alignedFigure 1 - DropDownList with Text not aligned

See that because Hospital names that come before => have different lengths, it doesn’t look good. Start and End dates are not aligned due to this.

So I thought about adding some caring to this and remembered that C# supports what I want to do. It’s called Composite Formatting. This when used with the Alignment Component allows some nice implementations.

The optional alignment component is a signed integer indicating the preferred formatted field width. If the value of alignment is less than the length of the formatted string, alignment is ignored and the length of the formatted string is used as the field width. The formatted data in the field is right-aligned if alignment is positive and left-aligned if alignment is negative. If padding is necessary, white space is used. The comma is required if alignment is specified.

Look at the following action method that lies within an ASP.NET MVC app. It’s responsible for adding list items to the dropdown show above…

[GET("Reports")]
public virtual ActionResult Index()
{
    ReportViewModel model = new ReportViewModel();

    // Getting the length of the lengthiest FictitiousName using Max query operator
    var maxLength = Database.Assessments.Max(a => a.Hospital.FictitiousName.Length);

    // Here’s the dynamic part: maxLength is used inside a format string to right align all strings, hence the minus sign. Doing this all strings will be equally left aligned (by maxLength) no matter their size.
    // {0}, {1} and {2} are positional parameters.
    string format = "{0, -" + maxLength + "} => {1} - {2}";

    List<SelectListItem> items = new List<SelectListItem>();

    foreach(Assessment a in Database.Assessments)
    {
        SelectListItem item = new SelectListItem();

        // Here's where the format string is used...
        item.Text = string.Format(format,
            a.Hospital.FictitiousName, a.StartDate.ToShortDateString(), a.EndDate.ToShortDateString());

        // This is necessary so that white spaces are respected when rendering the HTML code.
        item.Text = item.Text.Replace(" ", HttpUtility.HtmlDecode("&nbsp;"));

        item.Value = a.AssessmentId.ToString();

        items.Add(item);
    }

    model.Assessments = new SelectList(items.OrderBy(i => i.Text), "Value", "Text");

    return View(model);
}

With this code, now the result (really better to spot the dates) is this:

DropDownList with Text aligned using a format string dynamically builtFigure 2 - DropDownList with Text aligned using a format string dynamically built

maxLength in this case = 20. This is the length of “Unimed Volta Redonda” (the lengthiest string in the list) in this specific case. The format string uses this value to left align this and all other strings with smaller lengths “equally” adding white spaces to compensate the smaller strings.

One really import thing to take into consideration when doing what this post proposes is to use a monospaced font or fixed-width font, because its letters and characters each occupy the same amount of horizontal space. If you don’t use this kind of font, you won’t get the desired result.

This is the Razor view code:

<div id="reports">

@Html.LabelFor(m => m.Assessments)&nbsp; @Html.DropDownListFor(m => m.AssessmentId, Model.Assessments, string.Format(Localization.SelectValue2, Localization.Assessment), new { data_bind="value: selectedAssessment" } )

</
div>

So in order to make it work I added this CSS code:

#reports select
{
    font-family: 'Courier New'; /* well known monospaced font */
    width: auto;
}

Happy C# dynamic text aligning to everyone!