通过使用 LINQ 和 MVVM 过滤两个相同类型的 ObservableCollection 创建一个 ObservableCollection

Posted

技术标签:

【中文标题】通过使用 LINQ 和 MVVM 过滤两个相同类型的 ObservableCollection 创建一个 ObservableCollection【英文标题】:Create an ObservableCollection by filtering two ObservableCollections of the same type using LINQ and MVVM 【发布时间】:2020-03-21 01:22:30 【问题描述】:

我正在尝试创建一个 ObserverableCollection 以通过查看其他集合并添加目标集合中与源集合具有不同值的任何对象来填充网格视图。

我有一个模型:

public class LayerModel

    public string Name  get; set; 

    public string OnOff  get; set; 

    public string Freeze  get; set; 

    public string Color  get; set; 

    public string Linetype  get; set; 

    public string Lineweight  get; set; 

    public string Transparency  get; set; 

    public string Plot  get; set; 

在我的视图模型中该模型的两个 ObservableCollections:

public ObservableCollection<LayerModel> SourceDrawingLayers  get; set; 

public ObservableCollection<LayerModel> TargetDrawingLayers  get; set; 

冲突的集合:

public ObservableCollection<LayerModel> ConflictLayers get; set;

最后,一组要比较的目标图纸:

ObservableCollection<TargetDrawingModel> TargetDrawings get; set;

在应用程序中,要求用户选择源图形。提示用户OpenFileDialog 并选择一个绘图文件。此时,SourceDrawingLayers 是通过查看该文件中的每一层并创建集合的方法创建的。

接下来,用户必须选择一组目标图纸,以TargetDrawingModel 表示。选择添加到TargetDrawings

现在是有趣的部分。

我需要打开每个目标绘图并读取图层,然后将这些图层与 SourceDrawingLayers 进行比较,如果任何属性不同,我需要将其添加到 ConflictLayers

到目前为止,我已经尝试了一个令人讨厌的三重嵌套 foreach 语句,但它不能正常工作,所以我开始深入研究 LINQ,因为我的问题似乎有一个简单的解决方案,但我的结果很奇怪。

这是我目前所在的位置。我尝试使用“where”语句仅查看 LayerModel 中的 OnOff 属性,但生成的 ConflictLayers ObservableCollection 只是填充 TargetDrawing 中的每个层并按原样显示它们的设置。

    private void PopulateConflictLayers()
    
        foreach (TargetDrawingModel targetDrawingModel in TargetDrawings)
        
            DataAccess da = new DataAccess();
            TargetDrawingLayers = da.GetDrawingLayers(targetDrawingModel.DrawingPath);
            ConflictLayers = TargetDrawingLayers.Where(y => SourceDrawingLayers.Any(z => z.OnOff == y.OnOff));
        
    

我的目标是让ConflictLayers 成为TargetDrawingLayersLayerModels 的集合,其中 any 属性与SourceDrawingLayers.

我也尝试过使用Any 方法,但得到了完全相同的结果,我的ConflictLayers 只是在我的目标绘图中显示每个LayerModel,无论设置如何或它是否匹配SourceDrawingLayers 中的任何内容.

任何想法都会非常感激!

更新:我尝试了下面 reggaeguitar 提供的解决方案,结果是我的数据网格在我添加到集合中的源图形和目标图形中都显示了所有未过滤的图层。

我在 LayerModel 上实现了 IEquatable

 public bool Equals(LayerModel other)
    
        if (other == null)
            return false;
        return
        Name == other.Name
        && OnOff == other.OnOff
        && Freeze == other.Freeze
        && Color == other.Color
        && Linetype == other.Linetype
        && Lineweight == other.Lineweight
        && Transparency == other.Transparency
        && Plot == other.Plot;
    

并更新了我的方法如下:

 private void PopulateConflictLayers()
    
        foreach (TargetDrawingModel targetDrawingModel in TargetDrawings)
        
            DataAccess da = new DataAccess();
            TargetDrawingLayers = da.GetDrawingLayers(targetDrawingModel.DrawingPath);
            var s = TargetDrawingLayers.Except(SourceDrawingLayers).Union(SourceDrawingLayers.Except(TargetDrawingLayers));
            ObservableCollection<LayerModel> list = new ObservableCollection<LayerModel>(s);
            ConflictLayers = list;
        
    

我做错了什么?

【问题讨论】:

Linq 方法 Intersect 可能会对您有所帮助。确保在要比较的类上实现 IEquatable ConflictLayers = TargetDrawingLayers.Except(SourceDrawingLayers) ConflictLayers = TargetDrawingLayers.Except(SourceDrawingLayers).Union(SourceDrawingLayers.Except(TargetDrawingLayers) 我尝试了 reggaeguitar 和 Robert McKee 的建议,但没有得到很好的结果。我已经用详细信息编辑了我的问题。 您是否也覆盖了 GetHashCode?这可能是问题 【参考方案1】:

我找到了一个我想发布的解决方案。

我最终修改了我的代码:

ConflictLayers = TargetDrawingLayers.Where(i => !SourceDrawingLayers.Contains(i)).ToList();

我还在我的LayerModel 上实现了IEquatable 并覆盖了GetHashCode()。结果是我的ConflictLayers 现在正确填充了LayerModels,其属性与SourceDrawing 不同。

【讨论】:

您将 ConflictLayers 声明为 ObservableCollection。请注意,当 TargetDrawingLayers 或 SourceDrawingLayers 集合发生更改(添加、删除、...)时,ConflictLayers 不会反映该更改。

以上是关于通过使用 LINQ 和 MVVM 过滤两个相同类型的 ObservableCollection 创建一个 ObservableCollection的主要内容,如果未能解决你的问题,请参考以下文章

Kendo UI - 属性更改 MVVM

如何将相同的viewmodel设置为xamarin表单中的新mvvm中的两个视图

LINQ - 按相同功能过滤和排序的最有效方法

LINQ学习之旅

使用 Distinct() 过滤 Linq 中的重复记录

忽略重音和大小写的 LINQ