自定义ObservableCollection <t>的基本类型</t>

时间:2012-12-05 17:20:15

标签: c# sorting observablecollection

我有以下简化类:

public class BaseContainer
{
    public BaseContainer()
    {
        Children = new ObservableCollection<BaseContainer>();
    }
    public ObservableCollection<BaseContainer> Children { get; set; }
}

public class ItemA : BaseContainer
{
    public ItemA()
    {
        base.Children.Add(new ItemB() { ItemBName = "bb" });
        base.Children.Add(new ItemA() { ItemAName = "ab" });
        base.Children.Add(new ItemB() { ItemBName = "ba" });
        base.Children.Add(new ItemA() { ItemAName = "aa" });
    }
    public string ItemAName { get; set; }
}

public class ItemB : BaseContainer
{
    public string ItemBName { get; set; }
}

我正在尝试根据两个条件对ItemA.Children集合进行排序:

  1. 所有项目A必须在集合中排在第一位
  2. 项目A应按ItemAName排序
  3. 项目B应按ItemBName
  4. 排序

    所以在排序之后我会期待这样的事情:

    • ItemA - ItemAName =“aa”
    • ItemA - ItemAName =“ab”
    • ItemB - ItemBName =“ba”
    • ItemB - ItemBName =“bb”

    关于如何实现这一目标的任何想法?

    我能够按类类型名称排序:

            List<BaseContainer> temp = base.Children.ToList();
            temp.Sort((x, y) => string.Compare(x.GetType().Name, y.GetType().Name));
            base.Children.Clear();
            base.Children.AddRange(temp);
    

    但是姓名没有排序......

    谢谢!

3 个答案:

答案 0 :(得分:2)

var result = temp.OrderBy(x => x.GetType().Name).ThenBy(x => GetPropValue(x));

string GetPropValue(object o)
{
    Type t = o.GetType();
    var p = t.GetProperty("ItemAName");
    if (p != null)
    {
        return (string)p.GetValue(o, null);
    }
    p = t.GetProperty("ItemBName");
    return (string)p.GetValue(o, null);
}

答案 1 :(得分:1)

这将获得所有的A,由AName命令它们,然后连接所有按B名称排序的B.

var result = Children.OfType<ItemA>().OrderBy(a => a.ItemAName).Cast<Base>()
    .Concat(Children.OfType<ItemB>().OrderBy(b => b.ItemBName));

我不确定这是我要使用的设计......您可以考虑在基类中添加一些东西来促进这种排序。

答案 2 :(得分:1)

您可以通过指定ItemName来初始化项目,但BaseContainerItemAItemB都不会定义此类属性。

声明ItemName in the base class BaseContainer`。 item类自动继承此属性,无需在那里重新定义这样的字段。

public class BaseContainer
{
    public string ItemName { get; set; }

    ...
}

public class ItemA : BaseContainer
{
    // Inherits ItemName 
}

public class ItemB : BaseContainer
{
    // Inherits ItemName 
}

现在按如下方式对列表进行排序:

var result = base.Children
    .OrderBy(b => b.GetType().Name)
    .ThenBy(b => b.ItemName);

在排序之前无需将其存储到临时列表中。结果是IEnumerable<BaseContainer>。如果要将结果存储为列表,可以附加.ToList()

var result = base.Children
    .OrderBy(b => b.GetType().Name)
    .ThenBy(b => b.ItemName)
    .ToList();

<强>更新

根据您的评论,您没有共同的ItemName财产。 为什么?你真的应该有一个。重构你的课程。如果由于某种原因您不想在ItemName中使用BaseContainer,请创建抽象基类Item或让项目实现公共接口。

public abstract class Item : BaseContainer
{
    public string ItemName { get; set; }
}

public class ItemA : Item
{
}

public class ItemB : Item
{
}

或者

public interface IItem
{
    string ItemName { get; set; }
}

public class ItemA : BaseContainer, IItem
{
    public string ItemName { get; set; }
}

public class ItemB : BaseContainer, IItem
{
    public string ItemName { get; set; }
}

现在你可以像这样排序

var result = base.Children
    .OfType<Item> // or .OfType<IItem>
    .OrderBy(i => i.GetType().Name)
    .ThenBy(i => i.ItemName);

,结果将是IEnumerable<Item>IEnumerable<IItem>


另一个选择是覆盖每个对象从ToString继承的Syste.Object方法。

public class ItemA : BaseContainer
{
    public string ItemAName { get; set; }

    public override string ToString()
    {
        return "ItemA: " + ItemAName;
    }
}

这简化了排序,因为两个条件(按类型排序和按名称排序)可以一步完成。此字符串也将显示在列表框,组合框等中。

var result = base.Children
    .OrderBy(b => b.ToString());

如果无法做到这一点,请为此目的创建并实现一个接口:

public interface ISortable
{
    string SortString { get; }
}

public class ItemA : BaseContainer, ISortable
{
    public string ItemAName { get; set; }

    public string SortString { get { return "ItemA: " + ItemAName; } }
}

并按

排序
var result = base.Children
    .OfType<ISortable> 
    .OrderBy(b => b.SortString);