carlnelson.com

About Carl
Photos
C# Techniques
LEGO
Links

Problem: The client has a field of data that is a SQL varchar.  The data needs to be treated as a numeric for numeric values and string for string values.  The data is displayed in a DataGrid control and may be sorted by clicking the column header.

Natively, the data becomes a string when retrieved into a System.Data.DataTable.  The sort order provided does a string comparison.  If the data set is ('20', '21', '200'), the sort of the data as a string will return it in the order 20, 200, 21.  The desired sort order is the numeric, 20, 21, 200.

Solution:  A class was created called QuasiNumber:

 public class QuasiNumber : IComparable, IConvertible
 {
  private int IntData = int.MaxValue;
  private string StringData = "";
  public QuasiNumber(string Value)
  {
   StringData = Value;
   try
   {
    IntData = Convert.ToInt32(Value);
   }
   catch
   {
    IntData = int.MaxValue;
   }
  }
 }

that can hold either integer or string data.  The class constructor takes care of determining whether the data is integer or string.

The implementation of IComparable requires a CompareTo method of the class:

  public int CompareTo(object x)
  {
   int Results = 0;
   try
   {
    if (x.GetType() == typeof(QuasiNumber))
    {
     if ((int.MaxValue != IntData) && (int.MaxValue != ((QuasiNumber)x).IntData))
     {
      Results = IntData.CompareTo(((QuasiNumber)x).IntData);
     }
     else
     {
      Results = StringData.CompareTo(((QuasiNumber)x).StringData);
     }
    }
    else
    {
     if (int.MaxValue != IntData)
     {
      try
      {
       int Temp = Convert.ToInt32(x);
       Results = IntData.CompareTo(Temp);

      }
      catch
      {
       string Temp = Convert.ToString(x);
       Results = StringData.CompareTo(Temp);
      }
     }
     else
      Results = StringData.CompareTo(x);
    }
   }
   catch
   {
    Results = StringData.CompareTo(x);
   }
   return Results;
  }

I also implement the IConvertible interface, just for completeness.

The data is then retrieved from the database as a System.Data.DataTable.  A new DataColumn with data type QuasiNumber is created, and populated from values in the data column.

    SqlDataAdapter DataAdapter = new SqlDataAdapter(cmdSQL); //cmdSQL is a SqlCommand
    DataTable dtResults = new DataTable("Results");
    DataAdapter.Fill(dtResults);
    DataColumn dcDisplay = new DataColumn("DisplayField", typeof(QuasiNumber));
    dcDisplay.ReadOnly = false;
    dtResults.Columns.Add(dcDisplay);
    for (int i = 0; i < dtResults.Rows.Count; i++)
    {
     dtResults.Rows[i]["DisplayField"] = new QuasiNumber(dtResults.Rows[i]["ValueField"].ToString());
    }

Now, a click on the column header results in a call to the CompareTo method of the IComparable interface of QuasiNumber, resulting in the desired sort order.

Search
Feedback