Сравнение двух наборов ObservableCollection, чтобы увидеть, отличаются ли они - PullRequest
5 голосов
/ 01 января 2012

Я работаю над сравнением двух версий списка для формы настроек. Мне нужно знать, действительно ли пользователь вообще изменил список, и в этом случае, когда он нажмет «Сохранить», я на самом деле сохраню. Если они ничего не изменили, когда они нажмут «Сохранить», я не буду тратить впустую память / время на то, чтобы что-то не изменить.

В любом случае, как я могу сравнить две ObservableCollections, чтобы увидеть, отличаются ли они вообще?

Заранее спасибо!

Ответы [ 4 ]

4 голосов
/ 01 января 2012

Вы можете использовать метод 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' будет соответствовать числам B в приведенном выше примере кода ...


Также комментарий из ' Stonetip ' (кому спасибо) ...

More succinct: if(numbersA.Except(numbersB).Any()) { // do something } 
1 голос
/ 01 января 2012

То, как мы справляемся с этим, требует немного больше усилий, но оно может быть автоматизировано с помощью макросов VS или инструментов генерации кода, таких как CodeSmith.

Однако этот подход расширяем для любой конструкции пользовательского интерфейса, с которой связана коллекция, и не требует повторной реализации в пользовательском интерфейсе каждый раз, когда вам необходимо знать, есть ли изменения или нет.

Идея состоит в том, чтобы обновить флаги внутри коллекции и бизнес-объекта, чтобы определить, изменилось или нет членство в коллекции или какая-либо конкретная запись в коллекции.

Реализация довольно проста:

Добавление свойства HasChanged в класс бизнес-объекта.

Добавить свойство AnyDeleted в коллекцию. Это будет установлено только если элементы удалены из коллекции.

Инициализировать эти значения как ложные после чтения записей из БД.

(Теперь полудатая часть). Для каждого свойства в классе установите для свойства 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;
    }
0 голосов
/ 01 января 2012

Я думаю, вы сосредоточены на неправильном подходе.Не следует сравнивать содержимое двух списков, связанных с ListView, также потому, что количество элементов, которые они содержат, может быть чрезмерно большим.

  • Лучше сосредоточиться на определении единого (если это возможно) и единого способа изменения содержимого коллекции из API, предоставляя потребителю вашего класса общие сведения.способ изменить что-то в коллекции.Если этот метод используется, вы можете хранить логическое значение flag, которое идентифицирует, если что-то было изменено.

  • Или вы можете предположить, что если кто-то использует метод set внутри свойства привязанной коллекции, означает, что коллекция была изменена.

Другими словами, ретранслируйте или на предопределенный рабочий процесс вашего приложения или определяйте API для изменения содержимого, чтобы вы могли выяснить , когда и если содержимое коллекций было изменено.

И еще одно замечание: нет смысла позволять пользователю нажимать Save и не сохранять ,Если возможно нажать Save, команда, запрошенная пользователем, должна быть выполнена.Если вы настороженно относитесь к производительности (вы не хотите что-то сохранять, если это не изменилось с момента последнего сохранения), поэтому отключите кнопку Save, если сохранение не подходит.Другими словами, заполните UI и ведите себя так, как ожидается вашим приложением.Информирование пользователя о том, что приложение делает сейчас, а что нет.

0 голосов
/ 01 января 2012

Редактировать:

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;
      }
  }

Вы можете проверить эту переменную флага перед сохранением. Это сделало бы! если это правда, сохраните его!

...