对子节点进行正确排序,其中包括A.D.和B.C.树视图的子节点中的日期时间字符串

时间:2017-10-21 19:09:52

标签: c# sorting treeview

我使用了一个treeview组件来实现我的html编辑器。 我使用子节点用数据时间字符串记录历史事件,包括A.C.和B.C.时间。我测试过的树视图的子节点示例如下所示。

-History
  ﹂ 0123/05/05 B.C. event001
  ﹂ 2015/01/01 A.D. event002
  ﹂ 2017/01/21 A.D. event003
  ﹂ 2125/12/05 B.C. event000

排序后的正确结果应如下所示

-History
  ﹂ 2125/12/05 B.C. event000 
  ﹂ 0123/05/05 B.C. event001
  ﹂ 2015/01/01 A.D. event002
  ﹂ 2017/01/21 A.D. event003

我使用的代码只是simillar到以下帖子: Sorting child nodes of a treeview after populating the treeview in c# winforms

using System.Collections;
using System.Windows.Forms;
namespace TreeViewEditor
{
    public class NodeSorter : IComparer
    {
        public int Compare(object x, object y)
        {
                TreeNode tx = x as TreeNode;
                TreeNode ty = y as TreeNode;
                return string.Compare(tx.Text, ty.Text);
            }
    }
}

当子节点仅包含A.D.日期时间字符串时,它可以正常工作。我想知道当子节点同时包含A.D.和B.C.时如何正确排序。树视图中的日期时间字符串。

2 个答案:

答案 0 :(得分:1)

执行此操作的一种方法是使用类来表示日期,并在类上实现IComparable。这允许您自定义排序算法,以便B.C.日期按相反顺序排序(与A.D.日期相比)。

下面我创建了一个具有年,月,日属性的类,以及为B.C.设置为false的bool。日期。我添加了一个Parse()方法,可以使用您的一个示例字符串(没有“event”部分)并返回一个BCADDate对象。如果需要,添加“事件”属性以及从字符串中解析事件的能力将是微不足道的(下面的注释我可以添加它)。

基本上比较的工作方式如下:

  1. 如果日期没有相同的BC / AD名称,则BC名称首先出现
  2. 否则,比较年份,然后是月份,然后是天数,并返回不匹配的第一个的比较结果。通过乘以-1
  3. 来反转BC日期的结果
  4. 如果所有属性都匹配,则返回0
  5. 修改

    我还添加了IComparer接口的实现,以防有助于在树视图中使用它。

    以下是代码:

    class BCADDate : IComparable, IComparer
    {
        public int Year { get; set; }
        public int Month { get; set; }
        public int Day { get; set; }
        public bool IsAD { get; set; }
    
        public static BCADDate Parse(string input)
        {
            var result = new BCADDate();
    
            if (string.IsNullOrWhiteSpace(input))
                throw new ArgumentException("input cannot be null, empty, or whitespace");
    
            var dateADParts = input.Split(' ');
            var dateParts = dateADParts[0].Split('/');
    
            if (dateParts.Length < 3)
                throw new FormatException(
                    "The string must have three parts separated by the '/' character.");
    
            try
            {
                result.Year = int.Parse(dateParts[0]);
                result.Month = int.Parse(dateParts[1]);
                result.Day = int.Parse(dateParts[2]);
            }
            catch
            {
                throw new FormatException(
                    "All parts of the date portion must be valid integers.");
            }
    
            result.IsAD = (dateADParts.Length == 1)
                ? true  // A.D. is true if nothing is specified
                : dateADParts[1].IndexOf("A", StringComparison.OrdinalIgnoreCase) > -1;
    
            return result;
        }
    
        public int CompareTo(object obj)
        {
            var other = obj as BCADDate;
            if (other == null) return 1;
    
            var BCMultiplier = IsAD ? 1 : -1;
    
            // Use default comparers for our fields
            if (this.IsAD != other.IsAD)
                return this.IsAD.CompareTo(other.IsAD);
            if (this.Year != other.Year)
                return this.Year.CompareTo(other.Year) * BCMultiplier;
            if (this.Month != other.Month)
                return this.Month.CompareTo(other.Month) * BCMultiplier;
            if (this.Day != other.Day)
                return this.Day.CompareTo(other.Day) * BCMultiplier;
    
            return 0;
        }
    
        public int Compare(object x, object y)
        {
            var first = x as BCADDate;
            var second = y as BCADDate;
    
            if (first == null) return second == null ? 0 : -1;
            return first.CompareTo(second);
        }
    
        public override string ToString()
        {
            var bcad = IsAD ? "A.D." : "B.C.";
            return $"{Year:0000}/{Month:00}/{Day:00} {bcad}";
        }
    }
    

    以下是用法示例:

    var dates = new List<BCADDate>
    {
        BCADDate.Parse("0123/05/05 B.C."),
        BCADDate.Parse("2015/01/01 A.D."),
        BCADDate.Parse("2017/01/21 A.D."),
        BCADDate.Parse("2125/12/05 B.C.")
    };
    
    Console.WriteLine("Original ordering:");
    dates.ForEach(Console.WriteLine);
    
    dates.Sort();
    Console.WriteLine("------------------");
    
    Console.WriteLine("Sorted ordering:");
    dates.ForEach(Console.WriteLine);
    
    Console.Write("\nDone!\nPress any key to exit...");
    Console.ReadKey();
    

    <强>输出

    enter image description here

答案 1 :(得分:0)

基于Rufus L的解决方案,我在TreeView组件中实现了这个排序功能。令人惊讶的是,我只是对TreeView的NodeSorter进行了一些小修改。 Rufus L的解决方案在我的treeview应用程序中运行得很好。

修改后的源代码如下所示:

using System;
using System.Collections;
using System.Windows.Forms;
namespace TreeViewEditor
{
    class BCADDate : IComparable
    {
        public int Year { get; set; }
        public int Month { get; set; }
        public int Day { get; set; }
        public bool IsAD { get; set; }

        public static BCADDate Parse(string input)
        {
            var result = new BCADDate();

            if (string.IsNullOrWhiteSpace(input))
                throw new ArgumentException("input cannot be null, empty, or whitespace");

            var dateADParts = input.Split(' ');
            var dateParts = dateADParts[0].Split('/');

            if (dateParts.Length < 3)
                throw new FormatException(
                    "The string must have three parts separated by the '/' character.");

            try
            {
                result.Year = int.Parse(dateParts[0]);
                result.Month = int.Parse(dateParts[1]);
                result.Day = int.Parse(dateParts[2]);
            }
            catch
            {
                throw new FormatException(
                    "All parts of the date portion must be valid integers.");
            }

            result.IsAD = (dateADParts.Length == 1)
                ? true  // A.D. is true if nothing is specified
                : dateADParts[1].IndexOf("A", StringComparison.OrdinalIgnoreCase) > -1;

            return result;
        }

        public int CompareTo(object obj)
        {
            var other = obj as BCADDate;
            if (other == null) return 1;

            var BCMultiplier = IsAD ? 1 : -1;

            // Use default comparers for our fields
            if (this.IsAD != other.IsAD)
                return this.IsAD.CompareTo(other.IsAD);
            if (this.Year != other.Year)
                return this.Year.CompareTo(other.Year) * BCMultiplier;
            if (this.Month != other.Month)
                return this.Month.CompareTo(other.Month) * BCMultiplier;
            if (this.Day != other.Day)
                return this.Day.CompareTo(other.Day) * BCMultiplier;

            return 0;
        }
    }

    public class NodeSorter : IComparer
    {
        public int Compare(object x, object y)
        {
            TreeNode tx = x as TreeNode;
            TreeNode ty = y as TreeNode;
            BCADDate a = BCADDate.Parse(tx.Text);
            BCADDate b = BCADDate.Parse(ty.Text);
            return a.CompareTo(b);
        }
    }
}

我的申请中使用的代码如下所示:

TreeView2.TreeViewNodeSorter = new NodeSorter();