【问题标题】:How can I return in a ObsevableCollection<T> using C# Linq, all items if no one is selected or just selected items if at least one is selected?如何使用 C# Linq 在 ObsevableCollection<T> 中返回所有项目,如果没有选择任何项目,或者如果至少选择了一个项目,则只选择项目?
【发布时间】:2020-02-20 09:40:30
【问题描述】:

我正在尝试在以下情况下使用 Linq 和 Lambda 在 ObservableCollection&lt;MyClassSelectable&gt; 中获取 C# 中的项目:

  • 如果没有选择任何项目,则返回所有项目

或者

  • 如果至少选择了一项,则返回仅选定的项。

MyClassSelectable 有一个名为 Selectedbool 类型的属性。

是否可以只在一个 Linq 查询行中做到这一点?

谢谢。

【问题讨论】:

  • 它需要单个 Linq 查询的任何特殊原因?
  • 你能分享整个代码示例吗? Linq 方法在大多数情况下返回 IEnumerable,你不能返回 ObservableCollection
  • 只需要代码更紧凑,便于维护,不需要多行做同一个功能查询。

标签: c# linq lambda items


【解决方案1】:

您可以先按Selected 属性进行分组。如果有选择和未选择的项目,这将为您提供 2 个组,如果所有项目都已选择或未选择,则为 1 个组。然后,按所选属性对组进行排序。如果有 2 个组,这会将包含所选项目的组放在首位。然后,返回第一组。

ObservableCollection<MyClassSelectable> myClassesSelectable;

List<MyClassSelectable> result = myClassesSelectable
    // group by the Selected property
    .GroupBy(mcs => mcs.Selected)
    // order (=> true first, false second)
    .OrderByDescending(g => g.Key)
    // return the first
    .FirstOrDefault()
    ?.ToList();

【讨论】:

    【解决方案2】:
    return new ObservableCollection<MyClassSelectable>(myCol.Any(x => x.Selected)?myCol
    .Where(x => x.Selected):myCol)
    

    【讨论】:

    • 我也测试了这个解决方案。它返回与此答案相同的结果stackoverflow.com/a/60318825/12805184
    • 我不认为这算作一次查询。这只是利用内联 if 语句将所有内容堆叠成一行。
    【解决方案3】:

    要回答@Pavel Anikhouski 并更新@GregaMohorko 的答案,下面的代码正确地完成了这项工作。

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    
    namespace Test
    {
        public class MyClassSelectable
        {
            public bool Selected { get; set; }
            public string Name { get; set; } = "";
        }
    
        public class Class1
        {
    
            public ObservableCollection<MyClassSelectable> myClassesSelectable = new ObservableCollection<MyClassSelectable>();
    
            public Class1()
            {
                myClassesSelectable.Add(new MyClassSelectable { Selected = true, Name = "Item 1" });
                myClassesSelectable.Add(new MyClassSelectable { Selected = true, Name = "Item 2" });
                myClassesSelectable.Add(new MyClassSelectable { Selected = false, Name = "Item 3" });
                myClassesSelectable.Add(new MyClassSelectable { Selected = false, Name = "Item 4" });
    
                IEnumerable<MyClassSelectable> myCollection = myClassesSelectable
                                // group by the Selected property
                                .GroupBy(mcs => mcs.Selected)
                                // order (=> true first, false second)
                                .OrderByDescending(g => g.Key)
                                // return the first OR an empty collection if there are no items
                                .FirstOrDefault()
                                ?.ToList();
            }
    
        }
    }
    
    • 如果选择了 2 个项目,则返回这两个项目的列表。
    • 如果未选择任何项目,则返回所有 4 个项目。

    非常感谢@GregaMohorko 的工作。

    【讨论】:

    • 你可能应该在最后ToList() 之前添加一个问号,因为FirstOrDefault() 可以返回null,如果没有项目,它会抛出NullReferenceException。请看看我更新的答案。
    • 嗨@GregaMohorko,你是对的。我做了更新。最好的问候。
    【解决方案4】:

    您也可以在不使用 GroupBy() 的情况下实现相同的行为。

    class MainClass {
      public static void Main (string[] args) {
        var myCollection = new ObservableCollection<MyClassSelectable>();
    
        // Add some items of tyoe MyClassSelectable to myCollection here
        myCollection.Add(new MyClassSelectable() { Selected = true });
        myCollection.Add(new MyClassSelectable() { Selected = false });
        myCollection.Add(new MyClassSelectable() { Selected = true });
        myCollection.Add(new MyClassSelectable() { Selected = true });
    
    
        // Now get selected or all items
        var selected = GetSelectedItems(myCollection);
    
        Console.WriteLine($"Items selected: {selected.Count()}");
      }
    
      private static IEnumerable<MyClassSelectable> GetSelectedItems(ObservableCollection<MyClassSelectable> coll) {
        var selected = coll.Where(c => c.Selected);
        if (selected.Count() > 0) {
          return selected;
        }
        else {
          return coll;
        }
      }
    }
    

    【讨论】:

    • 你是对的,但问题的目的没有达到。它填充了几行代码。
    • 你是对的,但我建议这个解决方案的原因是你只迭代一次集合而不是迭代列表(对项目进行分组)然后排序真假键,最后再一次转换整个选择列表的集合。消除几行代码的开销如此之大?有时,最短的解决方案并不是最好的。
    • 我同意你的看法。但在我的具体情况下,CPU 和内存开销不如代码清晰重要。
    猜你喜欢
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 2019-04-02
    • 2020-05-10
    • 1970-01-01
    相关资源
    最近更新 更多