C# 我可以使用列表吗<;T>;和一份清单<;表达式>;要填充wpf数据网格?

C# 我可以使用列表吗<;T>;和一份清单<;表达式>;要填充wpf数据网格?,c#,wpf,C#,Wpf,我可以使用列表和列表来填充wpf数据网格吗 { var processes = Process.GetProcesses().ToList(); PopulateDataGrid( processes, x => x.ProcessName, x => GetSafeFilename( x ) ); } private string GetSafeFilename( Process p ) { try {

我可以使用
列表
列表
来填充wpf数据网格吗

  {
      var processes = Process.GetProcesses().ToList();
      PopulateDataGrid( processes, x => x.ProcessName, x => GetSafeFilename( x ) );  
  }
  private string GetSafeFilename( Process p )
  {
     try
     {
        return p.MainModule.FileName;
     }
     catch ( Exception )
     {
        return "";
     }
  }
其思想是,我希望能够传递一个表达式列表和参数列表来填充datagrid。我只想显示datagrid上的表达式列表

我还希望能够获得所选行的基础对象

我知道我可以使用匿名类型,如:

var list = processes.Select( x => new {TagObject = x, ProcessName = x.ProcessName, Filename = GetSafeFilename( x )} ).ToList();
但是,我必须确保不要将“TagObject”添加到数据网格中

有什么想法吗?我真的很喜欢语法的想法:

PopulateDataGrid( processes, x => x.ProcessName, x => GetSafeFilename( x ) ); 

但是我不知道如何实现它。

您希望提供一组表达式,并使用每个表达式在网格中创建自己的列。您必须解决一个主要问题:使用对象的属性的数据绑定来解决DataGrid列:

<DataGridTextColumn Header="ProcessName" Binding="{Binding ProcessName}" />
  • 或返回匿名类型的表达式。这样做的另一个好处是允许您将标题传递给列:

    PopulateDataGrid(processes, x => new { x.ProcessName, Path = x.MainModule.FileName });
    
  • 此外,我建议将其作为DataGrid上的扩展方法公开。签名可以如下所示:

    public static void PopulateDataGrid<TElement, TFieldsExpression>(this DataGrid dg, IEnumerable<TElement> itemsSource, Expression<Func<TElement, TFieldsExpression>> fieldsExpr) {
    }
    
    然后您可以编写以下方法:

    public static void PopulateDataGrid<TElement, TFieldsExpression>(this DataGrid dg, IEnumerable<TElement> itemsSource, Expression<Func<TElement, TFieldsExpression>> fieldsExpr) {
        dg.ItemsSource = itemsSource;
    
        dg.Columns.Clear();
    
        var fields = ParseFields(fieldsExpr);
        foreach (var (name, expr) in fields) {
            if (expr is MemberAccessExpression mexpr) {
                dg.Columns.Add(new DataGridTextColumn {
                    Header = name,
                    Binding = new Binding(mexpr.Member.Name)
                })
            } else {
                throw new ArgumentException("Unhandled expression type.");
            }
        }
    }
    
    注:大部分来自于伴随着一个。示例代码处理其他表达式类型、长路径链(例如
    x.MainModule.FileName
    )和对
    String.Format
    的方法调用


    助手扩展:

    // using System.Reflection;
    
    public static bool IsAnonymous(this Type type) =>
        type.HasAttribute<CompilerGeneratedAttribute>() && type.Name.Contains("Anonymous") && type.Name.ContainsAny("<>", "VB$");
    
    public static bool HasAttribute<TAttribute>(this MemberInfo mi, bool inherit = false) where TAttribute : Attribute =>
        mi.GetCustomAttributes(typeof(TAttribute), inherit).Any();
    
    public static bool ContainsAny(this string s, params string[] testStrings) =>
       testStrings.Any(x => s.Contains(x));
    
    //使用System.Reflection;
    公共静态布尔值不合法(此类型)=>
    type.HasAttribute()&&type.Name.Contains(“匿名”)&&type.Name.ContainsAny(“,”VB$”);
    公共静态bool HasAttribute(此MemberInfo mi,bool inherit=false),其中tatAttribute:Attribute=>
    GetCustomAttributes(typeof(tatAttribute),inherit).Any();
    公共静态bool ContainsAny(此字符串s,参数字符串[]testStrings)=>
    任何(x=>s.Contains(x));
    
    当你谈到表达式时,你的意思是,对吗?因为WPF有自己的类。我重写了我对这个问题的答案。我不确定我写原始答案时的想法。
    private static List<(string name, Expression expr)> ParseFields<TElement, TFieldsExpression>(Expression<Func<TElement, TFieldsExpression>> fieldsExpression) {
        var body = fieldsExpression.Body;
    
        switch (body) {
    
            // an array initialization with elements
            // (as opposed to an array initialization with bounds -- new int[5])
            case NewArrayExpression newArrayExpr when body.NodeType == ExpressionType.NewArrayInit:
                return newArrayExpr.Expressions.Select(x => ("", x)).ToList();
    
            // anonymous type
            // the IsAnonymous extension method is included at the end of the post
            case NewExpression newExpr when newExpr.Type.IsAnonymous():
                return newExpr.Constructor.GetParameters().Select(x => x.Name).Zip(newExpr.Arguments).ToList();
    
            default:
                throw new ArgumentException("Unhandled expression type.");
        }
    }
    
    public static void PopulateDataGrid<TElement, TFieldsExpression>(this DataGrid dg, IEnumerable<TElement> itemsSource, Expression<Func<TElement, TFieldsExpression>> fieldsExpr) {
        dg.ItemsSource = itemsSource;
    
        dg.Columns.Clear();
    
        var fields = ParseFields(fieldsExpr);
        foreach (var (name, expr) in fields) {
            if (expr is MemberAccessExpression mexpr) {
                dg.Columns.Add(new DataGridTextColumn {
                    Header = name,
                    Binding = new Binding(mexpr.Member.Name)
                })
            } else {
                throw new ArgumentException("Unhandled expression type.");
            }
        }
    }
    
    dg.PopulateDataGrid(list, x => new [] {x.ProcessName, x.HasExited, x.MachineName};
    
    // using System.Reflection;
    
    public static bool IsAnonymous(this Type type) =>
        type.HasAttribute<CompilerGeneratedAttribute>() && type.Name.Contains("Anonymous") && type.Name.ContainsAny("<>", "VB$");
    
    public static bool HasAttribute<TAttribute>(this MemberInfo mi, bool inherit = false) where TAttribute : Attribute =>
        mi.GetCustomAttributes(typeof(TAttribute), inherit).Any();
    
    public static bool ContainsAny(this string s, params string[] testStrings) =>
       testStrings.Any(x => s.Contains(x));