【问题标题】:How to Sort Listview Columns Containing Strings & Integers?如何对包含字符串和整数的 Listview 列进行排序?
【发布时间】:2013-06-25 10:42:56
【问题描述】:

一般信息

我有一个包含多列的 ListView。我使用了Microsoft Method to sort my ListView Columns。 ListView 由 SQL 查询填充,该查询将字符串和整数正确排序在一起(代码如下所示)。例如:

字符串和整数排序问题

以下JobNumber 字符串被视为已排序

“10”、“1”、“2”、“3”

使用我的 SQL 查询,它们会变成

“1”、“2”、“3”、“10”


SQL 字符串和整数排序器

这是我用来正确排序字符串和整数的查询

SELECT PK_BillHeader, JobNumber, Description
FROM dbo.BillHeaders 
ORDER BY Case IsNumeric(JobNumber) 
    When 1 Then Replicate('0', 50 - Len(JobNumber)) + JobNumber 
        Else JobNumber 
    End

这会输入零,直到得到我的 SQL 列的最大长度(50 个字符)减去 JobNumber 的当前长度。这样,所有内容都被视为一个字符串(包括整数),然后可以正确排序。


我的问题

当我单击 ListView 列标题(使其进行排序)时,它会停止对字符串和整数进行正确排序,就像对我的 SQL 查询所做的那样。相反,它将所有内容排序为一个字符串,再次复制我的“String & Integer”排序问题......更重要的是,如果我有十进制值(第二张图片) ,它把它们分类得很奇怪(查看我的比较代码

比较代码

Public Function [Compare](ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare
        Dim xItem As clsSortWrapper = CType(x, clsSortWrapper)
        Dim yItem As clsSortWrapper = CType(y, clsSortWrapper)

        Dim xText As String = xItem.sortItem.SubItems(xItem.sortColumn).Text
        Dim yText As String = yItem.sortItem.SubItems(yItem.sortColumn).Text

        If Decimal.TryParse(xText, vbNull) Then xText = xText.PadLeft(10, "0"c)
        If Decimal.TryParse(yText, vbNull) Then yText = yText.PadLeft(10, "0"c)
        Return xText.CompareTo(yText) * IIf(Me.ascending, 1, -1)
    End Function

有没有更简单的方法来实现我用字符串和整数对 ListView 进行排序的结果?


注意:

我省略了在此处发布ListView Sort code,因为它会使帖子聚集很多。我提供了详细解释的链接。

【问题讨论】:

  • 还有一个题外话提示:如果你熟悉 C#,我建议你添加标签 C#,因为它的关注者是 VB.NET 的十倍。
  • @FabianBigler 谢谢!我会这样做的

标签: c# vb.net listview sorting


【解决方案1】:

方法 #1:来自 Natural Comparer 的 Codesn-p 整个源代码为 here

这将按照您在问题中描述的方式进行排序,还支持罗马值(“D”、“X”等)。

int System.Collections.Generic.IComparer<string>.Compare(string string1, 
                                                 string string2)
{
  mParser1.Init(string1);
  mParser2.Init(string2);
  int result;
  do
  {
    if (mParser1.TokenType == TokenType.Numerical & 
                 mParser2.TokenType == TokenType.Numerical)
      // both string1 and string2 are numerical 
      result = decimal.Compare(mParser1.NumericalValue, mParser2.NumericalValue);
    else
      result = string.Compare(mParser1.StringValue, mParser2.StringValue);
    if (result != 0) return result;
    else
    {
      mParser1.NextToken();
      mParser2.NextToken();
    }
  } while (!(mParser1.TokenType == TokenType.Nothing & 
             mParser2.TokenType == TokenType.Nothing));  
  return 0; //identical 
}

方法 #2:简单的自定义比较器(没有罗马值)

class MyComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        int xVal, yVal;
        var xIsNumeric = int.TryParse( x, out xVal );
        var yIsNumeric= int.TryParse( y, out yVal );

        if (xIsNumeric && yIsNumeric)
            return xVal.CompareTo(yVal);
        if (!xIsNumeric && !yIsNumeric)
            return x.CompareTo(y);
        if (xIsNumeric )           
            return -1;
        return 1;   
    }
}

【讨论】:

  • +1 的帮助,谢谢。我会检查一下,看看我能用这个做什么
  • @Alex 重点是使用自定义 IComparer。两个比较器的工作方式相似。您可以仔细检查并给我反馈,哪种方法适合您。
  • 我在实现 NaturalComparer 时遇到了麻烦……“mParser”从何而来?我似乎在 VB.Net 中找不到等价物
  • @Alex:这就是我称之为 Codesn-p 的原因!整个代码源在 codeproject 上(链接在答案中):如果您不需要处理罗马值,我会推荐您第二种方法。
  • 是的,我知道,我在 CodeProject 上已经有一段时间了,我一直在尝试应用他们的修复。我可能自己找到了解决方案(希望如此)......如果没有,我会检查第二种方法。
【解决方案2】:

这是另一种方式。当您调用 CompareTo 时,在您的 Sort 代码中使用 0 填充字符串。

If Integer.TryParse(xText, VBNull) Then
      xText = xText.PadLeft(6, "0"c)
End If
If Integer.TryParse(yText, VBNull) Then
      yText = yText.PadLeft(6, "0"c)
End If
Return xText.CompareTo(yText) * IIf(Me.ascending, 1, -1)

这样“11004”将被比较为“011004”并出现在“110030”之前,但填充只是为了比较,该值仍然会显示为“11004”。

更新:

普通字符串现在将在没有填充的情况下进行排序。

【讨论】:

  • 酷! +1 效果很好。它对大部分内容进行了正确排序。滚动一段时间后,我看到了这个:i.imgur.com/b9bfSeT.png ... 字符串应该出现在数字之后。为什么有些数字介于两者之间?
  • @Alex 如果您只有数字格式的字符串,例如“11104”,这非常好,但如果您还有“普通”字符串,例如“Elec”或“TEMP”,则会失败。跨度>
  • 这些值必须由您的 SQL 查询返回。它们出现在那里是因为它们少于 6 个字符。一个简单的 Integer.TryParse 在进行比较之前检查值是否为整数,如果它们是整数则填充,如果不是则不填充
  • 很高兴它有效。请记住标记此回答谢谢。
  • @tinstaafl 如果我有这样的十进制值怎么办:i.imgur.com/DwgDHgy.png ...?我试过 Decimal.TryParse(..) 但也没有用。
猜你喜欢
  • 2014-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-12
  • 2022-01-11
  • 2020-05-14
  • 2022-11-23
  • 1970-01-01
相关资源
最近更新 更多