比较两个ObservableCollection(s)以查看它们是否不同

时间:2012-01-01 00:17:10

标签: c# wpf linq observablecollection

我正在为设置表单比较listview的两个版本。我需要知道用户是否真的修改了列表,在这种情况下,当他们点击“保存”时,我实际上会保存。如果他们没有改变任何东西,当他们点击“保存”时,我不会浪费记忆/时间重新保存他们没有改变的东西。

无论如何,我如何比较两个ObservableCollections以查看它们是否完全不同?

提前致谢!

4 个答案:

答案 0 :(得分:4)

您可以使用LINQ Except方法:生成两个序列的集合差异。

http://msdn.microsoft.com/en-us/library/system.linq.enumerable.except.aspx

考虑以下示例方法......

public void ExceptFunctioni()
{
    int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
    int[] numbersB = { 1, 3, 5, 7, 8 };
    IEnumerable<int> aOnlyNumbers = numbersA.Except(numbersB);
    if(aOnlyNumbers.Count()>0)
    {
        // do something
    }
}

在第一个集合上调用Except方法,并将第二个集合作为参数传递。结果将包含差异。然后,您可以查询结果并相应地采取措施。如果两个序列相等,则结果的计数将为零。

话虽如此,值得注意的是MVVM世界中的首选策略是使用此方法来控制是否启用了“保存”按钮。在这种方法中,如果两个集合相同,则“保存”按钮将被禁用,用户无法访问它。

但无论如何,LINQ方法提供了一种非常简洁的方式来实现你所追求的......

补充:看到你回复'Dumb'评论的评论,你的'oldList'将对应上面示例代码中的numberB ......


来自“comment”的Stonetip(对此表示感谢)......

More succinct: if(numbersA.Except(numbersB).Any()) { // do something } 

答案 1 :(得分:1)

我们处理这个问题的方式需要更多的工作,但可以使用VS宏或CodeSmith等代码生成工具自动完成。

但是,这种方法可以扩展到集合绑定的任何UI构造,并且每次需要知道是否有更改时都不必在UI中重新实现。

概念是更新集合和业务对象中的标志,以确定集合成员资格是否已更改或集合中的任何给定记录是否已更改。

实施非常简单:

将HasChanged属性添加到业务对象类。

将AnyDeleted属性添加到集合中。只有在从集合中删除项目时才会设置此项。

从数据库读取记录后,将这些值初始化为false。

(现在是半繁琐的部分)对于类中的每个属性,如果值实际更改,则将HasChanged属性设置为true。注意空值。例如:

    public bool IsSelected
    {
        get
        {
            return m_fIsSelected;
        }
        set
        {
            if (m_fIsSelected != value)
            {
                this.HasChanged = true;
                m_fIsSelected = value;
            }
        }
    }

修改集合,以便在删除记录时将AnyDeleted属性设置为true:

    protected override void RemoveItem(int index)
    {
        this.AnyDeleted = true;

        base.RemoveItem(index);
    }

最后,向集合添加一个方法,以指示是否有任何更改。这是您将调用以确定是否需要保存任何更改的方法:

   public bool HasAnyChanges()
    {
        // Exceptions are handled by the caller

        // If anything was deleted, return true
        if (this.AnyDeleted)
        {
            return true;
        }
        else
        {
            foreach (T theItem in this)
            {
                if (theItem.HasAnyChanges())
                {
                    return true;
                }
            }
        }

        return false;
    }

答案 2 :(得分:0)

编辑:

void ListView_ItemInserted(Object sender, ListViewInsertedEventArgs e)
  {
    if (e.Exception == null)
    {
      if (e.AffectedRows > 0)
      {
        flag = True;
      }
      else
      {
        flag = False;
      }
  }

void ListView_Itemdeleted(Object sender, ListViewDeletedEventArgs e)
  {
    if (e.Exception == null)
    {
      if (e.AffectedRows > 0)
      {
        flag = True;
      }
      else
      {
        flag = False;
      }
  }


void ListView_ItemUpdated(Object sender, ListViewUpdatedEventArgs e)
  {
    if (e.Exception == null)
    {
      if (e.AffectedRows > 0)
      {
        flag = True;
      }
      else
      {
        flag = False;
      }
  }

您可以在保存之前检查此标志变量。这样做!如果是真的,请保存!

答案 3 :(得分:0)

我认为,你正在关注错误的方法。您不应该将绑定的{2}列表的内容与ListView进行比较,因为它们包含的项目数量可能非常大。

  • 最好专注于定义单个(如果可行)和统一的方式,以便能够从API更改集合的内容,为您的类消费者提供一种能够更改的一般方法集合中的东西。如果使用该方法,则可以使用布尔值flag来标识某些内容是否已更改。

  • 或者你可以假设,如果有人在binded集合属性中使用set方法,则表示集合已更改。

换句话说,继续或在应用程序的预定义工作流程上,或定义API以更改内容,这样您就可以在和时找出如果< / em>集合的内容已更改。

另一个概念是:让用户点击Save不保存是没有意义的。如果可以单击Save,则必须执行用户请求的命令。如果您对性能保持警惕(您不想保存某些内容,如果它没有从上次保存更改),请禁用Save按钮,如果保存不合适。换句话说,进行UI填充并按照您的应用预期行事。让用户明白应用现在做什么以及不做什么。