8

I have the following strings:

"String 1"

"String 2"

"String 3"

"String 15"

"String 17"

I want the strings to be sorted as above. However, when I use SortDescription to sort my list, I get the following output:

"String 1"

"String 15"

"String 17"

"String 2"

"String 3"

I understand there are algorithms to accomplish this, however is there a way to do this with the built in functionality of SortDescription?

private void SortCol(string sortBy, ListSortDirection direction)
{
        ICollectionView dataView =
          CollectionViewSource.GetDefaultView(ListView.ItemsSource);

        dataView.SortDescriptions.Clear();

        SortDescription sd = new SortDescription(sortBy, direction);
        dataView.SortDescriptions.Add(sd);
        dataView.Refresh();
}

sortby is the property name of the property in my view model that represents the column I want to be sorted.

It seems like my only two sorting options are Ascending and Descending. But the way that it's sorts the CollectionView is not the way I would like my strings to be sorted. Is there an easy way to solve this?

jsirr13
  • 944
  • 2
  • 12
  • 38
  • Please show some code for us to work from.. – Simon Whitehead Mar 11 '13 at 22:27
  • http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html – I4V Mar 11 '13 at 22:34
  • Thanks for the comments, but I don't know how to do that with a ListView. Here's something pretty close I want to do this a ListView: http://stackoverflow.com/questions/10582996/how-to-sort-by-integer-in-a-listitemcollection-in-wpf – jsirr13 Mar 11 '13 at 22:50
  • 1
    @jsirr13, I think you are on the right track there! – failedprogramming Mar 11 '13 at 22:54
  • 5
    Marking this as a duplicate was wrong. The context of the question is totally different. Of course someone could write an algorithm to do the sorting in any language but this has to do with xaml and view bindings to view model properties. – shawn1874 Feb 06 '15 at 01:10
  • 2
    @shawn1874 agreed - this answer specifically helped me to discover the 'CustomSort' property on the collection view, which i had overlooked. I would not have learnt about this in a generic sort algorithm question. – Xcalibur Apr 09 '15 at 15:26

2 Answers2

8

Figured it out thanks to the link: Natural Sort Order in C#

[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    public static extern int StrCmpLogicalW(string psz1, string psz2);
}

public sealed class NaturalStringComparer : IComparer<string>
{
    public int Compare(object a, object b)
    {
        var lhs = (MultiItem)a;
        var rhs = (MultiItem)b;
        //APPLY ALGORITHM LOGIC HERE
        return SafeNativeMethods.StrCmpLogicalW(lhs.SiteName, rhs.SiteName);
    }
}

And here's how I use the above algorithm comparer:

    private void SortCol()
    {
        var dataView =
                      (ListCollectionView)CollectionViewSource.GetDefaultView(ListViewMultiSites.ItemsSource);
        dataView.CustomSort = new NaturalOrderComparer();
        dataView.Refresh();
    }
Community
  • 1
  • 1
jsirr13
  • 944
  • 2
  • 12
  • 38
  • if you don't want to use a dll import, it is easy to write your own comparer. Refer to this link for code. http://www.dotnetperls.com/alphanumeric-sorting – failedprogramming Mar 12 '13 at 01:37
  • What's the downside to using a dll import, just wondering? – jsirr13 Mar 12 '13 at 17:38
  • I think there might be some considerations when using dll imports, e.g. disposing unmanaged resources, small increase in file size, no access to source code. However, I don't believe I'm knowledgeable enough to give you a good answer. With this specific dll, if you read the link carefully, you will see that the functionality fluctuates depending on OS. You will need to decide if that is a problem for you. – failedprogramming Mar 12 '13 at 23:17
  • If you prefer a managed solution (no native code), you could use my [NaturalSort](https://unclassified.software/source/naturalsort) class. It also adds more features to customise the order. – ygoe Mar 10 '20 at 10:59
  • Another issue: This only works with a single column. It cannot replace the use of multiple SortDescriptions, unless you give up its flexibility and hard-code the multi-column sort in the custom comparer. Not usable if the user can sort by clicking on column headers, not even with a single column then. – ygoe Mar 10 '20 at 11:02
  • 2
    Used this, it works great but `NaturalStringComparer` has to implement `IComparer`, not the generic version. – Maxence Jun 21 '21 at 12:56
2

You could use Linq

var list = new List<string>
{
   "String 1",
   "String 17",
   "String 2",
   "String 15",
   "String 3gg"
};

var sort = list.OrderBy(s => int.Parse(new string(s.SkipWhile(c => !char.IsNumber(c)).TakeWhile(c => char.IsNumber(c)).ToArray())));

Returns:

   "String 1",
   "String 2",
   "String 3gg"
   "String 15",
   "String 17",
sa_ddam213
  • 42,848
  • 7
  • 101
  • 110