Blogs

Paul Kimmel's Blog

Right Justify Content in an ASPxComboBox

     

This blog is written as a partial response to support ID Q241581—ASPxListBox – Right Justify Column. The example uses an ASPxComboBox, but the same approach should work with the ASPxListBox.

The original query had a couple of parts: right justify numeric amounts and multi-list column sorting. The latter—supporting sorting by clicking on a column header is not supported. In this instance an ASPxGridView and ASPxListBox will basically provide the same functionality. To justify the data in a multi-column combobox (or listbox) the key is to not justify the first column even because this is using an incremental search. You can justify additional numeric columns using SQL. A couple of possible solutions are provided here.

Option 1

The ASPxComboBox has an ItemStyle.HorizontalAlign property. set this property to Right and all items will be displayed to the right. of course, if you want number aligned to the right then this won’t create the desired effect.

Option 2

To pad columns to the right embed right justification in the SQL statement. Assume you are selecting the ProductID. ProductName, and UnitPrice from the Northwind.Products table. You can set the column width of the UnitPrice column to 100 pixels and eyeball the width by playing with padding characters. The following SQL statement pads UnitPrice: given 100px width for UnitPrice padding to right for a total length of 20 looks about right in IE8 and Google Chrome. This may produce different results in different browsers, but you may find that it works for you.

SelectCommand="SELECT ProductID, ProductName, RIGHT(REPLICATE(' ', 20) + CAST(UnitPrice AS varchar(20)), 20) AS UnitPrice
FROM Products" onselecting="SqlDataSource1_Selecting">

Option 3

Implement an onselecting event handler for the SqlDataSource SelectCommand and dynamically write the SQL and adjust the padding based on the font. This may not work in all browsers because fonts may be rendered differently. Even if you find a great pixel-to-character width conversion function some fonts have different widths for each character, resulting in spotty results.

protected void SqlDataSource1_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
{
  "SELECT ProductID, ProductName, RIGHT(REPLICATE(' ', {0}) +" +
  "CAST(UnitPrice AS varchar({0})), {0}) AS UnitPrice " +
  "FROM Products";

  double width = ((DevExpress.Web.ASPxEditors.WebColumnBase)
    (ASPxComboBox1.Columns[2])).Width.Value;

  // convert pixels to strength width here

  e.Command.CommandText = string.Format(sql, 20);

}

Option 4

Run a solution and look at the generated source. The class rendered for the UnitPrice is dxeLTM (see Listing 1). This is a default class applied by the DevExpress renderer. (ListBoxItems are rendered as <td> tags with this class applied. Define a embedded style that provides a text-align attribute and add the !important declaration which increases the weight of a style rule. The embedded style in Listing 2 will right-align the UnitPrice.

Listing 1: How the UnitPrice is rendered as HTML.

<td class="dxeListBoxItem dxeFTM" style="width:120px;">1</td><td class="dxeListBoxItem dxeTM" style="width:120px;">Chai</td><td class="dxeListBoxItem dxeLTM" style="width:100px;">18.0000</td>

Listing 2: An embedded style that right aligns the third column by class name, determined by examining the rendered HTML.

<head id="Head1" runat="server">
    <title></title>

    <style type="text/css">
      .dxeLTM
      {
        text-align:right!important;
        border-color: Red!important;
      }
    </style>

</head>

I added the red border so you can see that the style is applied to just the UnitPrice column. Listing 3 contains the ASPX that will let you tinker with the possible solutions, and Listing 4 contains the supporting code-behind. There are some caveats to be applied here:

Caveat 1: Calculating optimal width based on fonts may not render well due to different character widths in some font families.
Caveat 2: Don’t right-align the first column using SQL padding because this will disrupt the Incremental Filtering mechanism.
Caveat 3: Depending on embedded styles and rendered names may break in future releases and additional columns will have different class names. You will have to check the actual class name, especially if you add columns or update your version of DevExpress controls. Document tricky stuff like this carefully and post where everyone can figure out what is going on.

The question you may have “should I do this”? The answer is you betcha. You can use hacks and kludges—sort of like adding duct tape—if the benefits give you that added cool factor and its the only solution available. However, the presence of physical duct tape is always evident to just about any practitioner, but code-duct-tape sometimes needs to be pointed out so document carefully. I plugged in little features in projects, especially if a customer demands I do so. It generally takes extra care, testing, and some careful documentation, but the customer is always right.

Unfortunately too much of this kind of thing can blow schedules, complicate testing, result in behavior that is different across browsers, so plan accordingly.

Listing 3: The ASPX that will let you explore variations on a solution.

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<%@ Register assembly="DevExpress.Web.ASPxEditors.v9.2, Version=9.2.8.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" namespace="DevExpress.Web.ASPxEditors" tagprefix="dxe" %>

<%@ Register assembly="DevExpress.Web.ASPxGridView.v9.2, Version=9.2.8.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" namespace="DevExpress.Web.ASPxGridView" tagprefix="dxwgv" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>

    <style type="text/css">
      .dxeLTM
      {
        text-align:right!important;
        border-color: Red!important;
      }
    </style>

</head>

<body>

    <form id="form1" runat="server">
    <div>
      <dxe:ASPxComboBox ID="ASPxComboBox1" runat="server" ClientInstanceName="Combo"
        DataSourceID="SqlDataSource1" EnableIncrementalFiltering="True"
        TextField="ProductName" ValueField="ProductID" ValueType="System.Int32"
        >
        <Columns>
          <dxe:ListBoxColumn Caption="ID" FieldName="ProductID" />
          <dxe:ListBoxColumn Caption="Name" FieldName="ProductName" />
          <dxe:ListBoxColumn Caption="Unit Price" FieldName="UnitPrice" Width="100px"  />
        </Columns>
      </dxe:ASPxComboBox>
      <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
        SelectCommand="SELECT ProductID, ProductName, RIGHT(REPLICATE(' ', 20) + CAST(UnitPrice AS varchar(20)), 20) AS UnitPrice
        FROM Products" onselecting="SqlDataSource1_Selecting">
      </asp:SqlDataSource>
    </div>
    </form>
</body>
</html>

Listing 4: The code-behind containing the injected SQL based on list box item width. (You will have to provide a conversion forumla for pixels to text-width.)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }
    protected void SqlDataSource1_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
    {
      string sql =
        "SELECT ProductID, ProductName, UnitPrice " +
        "FROM Products";

      //"SELECT ProductID, ProductName, RIGHT(REPLICATE(' ', {0}) +" +
      //"CAST(UnitPrice AS varchar({0})), {0}) AS UnitPrice " +
      //"FROM Products";

      double width = ((DevExpress.Web.ASPxEditors.WebColumnBase)
        (ASPxComboBox1.Columns[2])).Width.Value;

      e.Command.CommandText = sql;// string.Format(sql, 20);

    }
}

Published Dec 18 2009, 08:32 PM by Paul Kimmel (DevExpress)
Bookmark and Share

Comments

No Comments
More from DevExpress
Live Chat
Have a pre-sales question?
Need assistance with your evaluation?
We are here to help.
Chat is one of the many ways you can contact members of the DevExpress Team. We are available Monday-Friday between 8:30am and 5:00pm Pacific Time.
If you need additional product information, require pre-sales assistance, or want help with your order, write to us at info@devexpress.com or call us at
+1 (818) 844-3383.