C# 按属性名称排列的订单列表
我编写了一个函数,用于在单击列标题时对ListView进行排序。我现在希望该函数适用于任何列。我的第一个想法是传递一个表示列中显示的属性的字符串,并使用C# 按属性名称排列的订单列表,c#,wpf,data-binding,caliburn.micro,C#,Wpf,Data Binding,Caliburn.micro,我编写了一个函数,用于在单击列标题时对ListView进行排序。我现在希望该函数适用于任何列。我的第一个想法是传递一个表示列中显示的属性的字符串,并使用if或switch按正确的属性排序,例如: private bool sortOrder = false; public void SortCol(string property) { OUModel ou = ADRoot.Descendants().Where(node => node.IsSelected == true).F
if
或switch
按正确的属性排序,例如:
private bool sortOrder = false;
public void SortCol(string property)
{
OUModel ou = ADRoot.Descendants().Where(node => node.IsSelected == true).FirstOrDefault() as OUModel;
if (ou != null)
{
switch (property)
{
case "Name":
if (sortOrder)
{
ou.Computers = new List<RemoteComputer>(ou.Computers.OrderBy(c => c.Name));
}
else
{
ou.Computers = new List<RemoteComputer>(ou.Computers.OrderByDescending(c => c.Name));
}
break;
case "LastUpdated":
if (sortOrder)
{
ou.Computers = new List<RemoteComputer>(ou.Computers.OrderBy(c => c.LastUpdated));
}
else
{
ou.Computers = new List<RemoteComputer>(ou.Computers.OrderByDescending(c => c.LastUpdated));
}
break;
// etc...
}
sortOrder = !sortOrder;
}
}
private bool sortOrder=false;
公共void SortCol(字符串属性)
{
OUModel ou=ADRoot.subjects()。其中(node=>node.IsSelected==true)。FirstOrDefault()作为OUModel;
如果(ou!=null)
{
交换机(属性)
{
案例“名称”:
如果(排序器)
{
ou.Computers=新列表(ou.Computers.OrderBy(c=>c.Name));
}
其他的
{
ou.Computers=新列表(ou.Computers.OrderByDescending(c=>c.Name));
}
打破
案例“LastUpdated”:
如果(排序器)
{
ou.Computers=新列表(ou.Computers.OrderBy(c=>c.LastUpdated));
}
其他的
{
ou.Computers=新列表(ou.Computers.OrderByDescending(c=>c.LastUpdated));
}
打破
//等等。。。
}
sortOrder=!sortOrder;
}
}
但这显然会变得相当漫长和重复。相反,我想知道我是否可以通过财产本身。但是我试图从XAML(使用Caliburn.Micro操作)传递属性类型,但不知道如何传递
private bool sortOrder = false;
public void SortCol<T>(Func<RemoteComputer, T> property)
{
OUModel ou = ADRoot.Descendants().Where(node => node.IsSelected == true).FirstOrDefault() as OUModel;
if (ou != null)
{
if (sortOrder)
{
ou.Computers = new List<RemoteComputer>(ou.Computers.OrderBy(property));
}
else
{
ou.Computers = new List<RemoteComputer>(ou.Computers.OrderByDescending(property));
}
sortOrder = !sortOrder;
}
}
private bool sortOrder=false;
公共无效SortCol(Func属性)
{
OUModel ou=ADRoot.subjects()。其中(node=>node.IsSelected==true)。FirstOrDefault()作为OUModel;
如果(ou!=null)
{
如果(排序器)
{
ou.Computers=新列表(ou.Computers.OrderBy(属性));
}
其他的
{
ou.Computers=新列表(ou.Computers.OrderByDescending(属性));
}
sortOrder=!sortOrder;
}
}
XAML:
<!-- Name Spaces
xmlns:models="clr-namespace:MyProject.Models"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cal="http://www.caliburnproject.org"
-->
<!-- TreeView the ListView is bound to -->
<TreeView x:Name="ADTree" ItemsSource="{Binding ADRoot.Children}">
<!-- -->
<ListView x:Name="ADComputers" ItemsSource="{Binding SelectedItem.Computers, ElementName=ADTree, Mode=TwoWay}" SelectionMode="Multiple" ItemContainerStyle="{DynamicResource RemoteComputerItem}">
<ListView.View>
<GridView>
<GridViewColumn x:Name="Name" Width="120" DisplayMemberBinding="{Binding Name}">
<GridViewColumn.Header>
<GridViewColumnHeader x:Name="SortName" Content="Computer Name">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="SortCol">
<!-- Trying to pass type here, but nested types are not supported. Don't know how else I can do this -->
<cal:Parameter Value="{x:Type models:RemoteComputer.Name}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<!-- Other Columns -->
</GridView>
</ListView.View>
</ListView>
class ADTreeViewModel : OUModel
{
public OUModel ADRoot { get; set; } = new OUModel(null, false); // <<< TreeView is bound to this, and ListView is bound to TreeView.SelectedItem.Computers
}
class OUModel : PropertyChangedBase, ITreeViewItemViewModel
{
private List<RemoteComputer> computers = new List<RemoteComputer>();
public List<RemoteComputer> Computers { get { return computers; } set { computers = value; NotifyOfPropertyChange(); } }
}
class RemoteComputer : PropertyChangedBase
{
public string Name
{
get { return name; }
set { name = value; NotifyOfPropertyChange(() => Name); }
}
// Shortening the other properties, but you get the idea...
public IPAddress IP { //etc }
public ComputerStatus Status { //etc }
public DateTime LastUpdated { //etc }
// and so on...
}
课程等:
<!-- Name Spaces
xmlns:models="clr-namespace:MyProject.Models"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cal="http://www.caliburnproject.org"
-->
<!-- TreeView the ListView is bound to -->
<TreeView x:Name="ADTree" ItemsSource="{Binding ADRoot.Children}">
<!-- -->
<ListView x:Name="ADComputers" ItemsSource="{Binding SelectedItem.Computers, ElementName=ADTree, Mode=TwoWay}" SelectionMode="Multiple" ItemContainerStyle="{DynamicResource RemoteComputerItem}">
<ListView.View>
<GridView>
<GridViewColumn x:Name="Name" Width="120" DisplayMemberBinding="{Binding Name}">
<GridViewColumn.Header>
<GridViewColumnHeader x:Name="SortName" Content="Computer Name">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="SortCol">
<!-- Trying to pass type here, but nested types are not supported. Don't know how else I can do this -->
<cal:Parameter Value="{x:Type models:RemoteComputer.Name}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<!-- Other Columns -->
</GridView>
</ListView.View>
</ListView>
class ADTreeViewModel : OUModel
{
public OUModel ADRoot { get; set; } = new OUModel(null, false); // <<< TreeView is bound to this, and ListView is bound to TreeView.SelectedItem.Computers
}
class OUModel : PropertyChangedBase, ITreeViewItemViewModel
{
private List<RemoteComputer> computers = new List<RemoteComputer>();
public List<RemoteComputer> Computers { get { return computers; } set { computers = value; NotifyOfPropertyChange(); } }
}
class RemoteComputer : PropertyChangedBase
{
public string Name
{
get { return name; }
set { name = value; NotifyOfPropertyChange(() => Name); }
}
// Shortening the other properties, but you get the idea...
public IPAddress IP { //etc }
public ComputerStatus Status { //etc }
public DateTime LastUpdated { //etc }
// and so on...
}
class-ADTreeViewModel:OUModel
{
public-OUModel-ADRoot{get;set;}=new-OUModel(null,false);//您不需要开关。如果您想通过名称访问属性,您可以创建一个表达式来构建函数
private bool sortOrder=false;
公共void SortCol(字符串propName)
{
OUModel ou=ADRoot.subjects()。其中(node=>node.IsSelected==true)。FirstOrDefault()作为OUModel;
如果(ou!=null)
{
如果(排序器)
ou.Computers=ou.Computers.OrderBy(GetProperty(propName)).ToList();
其他的
ou.Computers=ou.Computers.OrderByDescending(GetProperty(propName)).ToList();
sortOrder=!sortOrder;
}
}
//此方法创建一个表达式
//并返回其编译后的()resutl.Func
//因此,您可以在orderBy方法中使用这个'Func'。
公共函数GetProperty(字符串属性名称)
{
//q=>
ParameterExpression param=表达式参数(typeof(T),“q”);
//q.propertyName
//例如:q.Name
MemberExpression member=Expression.PropertyOrField(参数,propertyName);
//将属性类型更改为object(因为我们希望使用类属性或字段的所有可能类型)
var body=Expression.Convert(成员,typeof(对象));
//创建表达式
var property=Expression.Lambda(body,param);
//返回一个Func
返回property.Compile();
}
更新
此外,您可以使用此扩展类向整个应用程序中的列表添加OrderBy字符串支持。这也适用于IQueryable查询
公共静态类OrderByExtensions
{
公共静态IOrderedEnumerable OrderByDescending(此IEnumerable列表,字符串propertyName)
{
return list.OrderByDescending(GetPropertyFunc(propertyName));
}
公共静态IQueryable OrderByDescending(此IQueryable列表,字符串propertyName)
{
return list.OrderByDescending(GetPropertyExpression(propertyName));
}
公共静态IOrderedEnumerable OrderBy(此IEnumerable列表,字符串propertyName)
{
return list.OrderBy(GetPropertyFunc(propertyName));
}
公共静态IQueryable OrderBy(此IQueryable列表,字符串propertyName)
{
return list.OrderBy(GetPropertyExpression(propertyName));
}
私有静态表达式GetPropertyExpression(字符串propertyName)
{
ParameterExpression param=表达式参数(typeof(T),“q”);
MemberExpression member=Expression.PropertyOrField(参数,propertyName);
var body=Expression.Convert(成员,typeof(对象));
返回表达式.Lambda(body,param);
}
私有静态函数GetPropertyFunc(字符串propertyName)
{
返回GetPropertyExpression(propertyName.Compile();
}
}
用法:
// eg. propName = "Name";
ou.Computers = ou.Computers.OrderByDescending(propName).ToList();
// or
ou.Computers = ou.Computers.OrderBy(propName).ToList();
非常好,谢谢。请你解释一下GetProperty
方法好吗?@Daniel我在每个步骤上都添加了一些注释。希望如此help@Daniel如果您不介意,请将您的问题标题更改为类似于OrderBy list by property name
,这样您可以帮助其他有类似问题的人。