C# 带有基类型的ObservableCollection的自定义排序
我有以下简化课程:C# 带有基类型的ObservableCollection的自定义排序,c#,sorting,observablecollection,C#,Sorting,Observablecollection,我有以下简化课程: public class BaseContainer { public BaseContainer() { Children = new ObservableCollection<BaseContainer>(); } public ObservableCollection<BaseContainer> Children { get; set; } } public class ItemA : Base
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集合进行排序:
所有项目A必须在集合中排在第一位
项目A应按项目名称排序
项目B应按项目名称排序
所以在分类之后,我会期待这样的事情:
var result = base.Children
.OrderBy(b => b.GetType().Name)
.ThenBy(b => b.ItemName);
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);
但是名字没有排序
谢谢 这将获得所有A,按AName订购,然后按B名称订购所有B
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);
}
var result = Children.OfType<ItemA>().OrderBy(a => a.ItemAName).Cast<Base>()
.Concat(Children.OfType<ItemB>().OrderBy(b => b.ItemBName));
我不确定这是不是我会选择的设计。。。您可以考虑添加一些基类来促进这种排序。 < P>这将得到所有的A,用AName排序,然后用B名称排序所有的B。p>
var result = Children.OfType<ItemA>().OrderBy(a => a.ItemAName).Cast<Base>()
.Concat(Children.OfType<ItemB>().OrderBy(b => b.ItemBName));
我不确定这是不是我会选择的设计。。。您可以考虑添加一些基类来促进这种排序。< P>您通过指定ItMeN名字初始化这些项,但是BaseCeNeReor、ItMeA和ItMeb都没有定义这样的属性。 在基本类BaseContainer“”中声明ItemName。项目类自动继承此属性,不需要在其中重新定义此类字段
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。如果要将结果存储为列表,可以附加.ToList
var result = base.Children
.OrderBy(b => b.GetType().Name)
.ThenBy(b => b.ItemName)
.ToList();
更新
根据您的评论,您没有公共ItemName属性。为什么?你真的应该有一个。重构你的类。如果出于某种原因,您不想在BaseContainer中使用ItemName,请创建一个抽象基类项,或者让这些项实现一个公共接口
public abstract class Item : BaseContainer
{
public string ItemName { get; set; }
}
public class ItemA : Item
{
}
public class ItemB : Item
{
}
或
现在你可以这样分类了
var result = base.Children
.OfType<Item> // or .OfType<IItem>
.OrderBy(i => i.GetType().Name)
.ThenBy(i => i.ItemName);
这简化了排序,因为按类型排序和按名称排序都可以在一个步骤中完成。此字符串也将显示在列表框、组合框等中
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);
您可以通过指定ItemName来初始化项,但BaseContainer、ItemA和ItemB都没有定义这样的属性 在基本类BaseContainer“”中声明ItemName。项目类自动继承此属性,不需要在其中重新定义此类字段
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。如果要将结果存储为列表,可以附加.ToList
var result = base.Children
.OrderBy(b => b.GetType().Name)
.ThenBy(b => b.ItemName)
.ToList();
更新
根据您的评论,您没有公共ItemName属性。为什么?你真的应该有一个。重构你的类。如果出于某种原因,您不想在BaseContainer中使用ItemName,请创建一个抽象基类项,或者让这些项实现一个公共接口
public abstract class Item : BaseContainer
{
public string ItemName { get; set; }
}
public class ItemA : Item
{
}
public class ItemB : Item
{
}
或
现在你可以这样分类了
var result = base.Children
.OfType<Item> // or .OfType<IItem>
.OrderBy(i => i.GetType().Name)
.ThenBy(i => i.ItemName);
这简化了排序,因为按类型排序和按名称排序都可以在一个步骤中完成。此字符串也将显示在列表框、组合框等中
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);
我想到了这一点,但对我来说不起作用。项目A和项目B不继承公共ItemName属性。我分别有ItemAName和ItemBName属性…@AdolfoPerez但是你的例子说newitemb{ItemName=bb}我想到了这个,但是在我的例子中不起作用。项目A和项目B不继承公共ItemName属性。我分别有ItemAName和ItemBName属性…@AdolfoPerez,但是你的例子说新的ItemB{ItemName=bb}我对这个做了一点修改,但是我喜欢这个想法,谢谢你的帮助!:var result=Children.OfType.OrderBya=>a.ItemAName.ConcatChildren.OfType.OrderByb=>b.ItemBName.ToList;我对此做了一点修改,但我喜欢这个主意,谢谢你的帮助!:var result=Children.OfType.OrderBya=>a.ItemAName.ConcatChildren.OfType.OrderByb=>b.ItemBName.ToList;