WPF: удалять элементы из bindong ObservableCollection через цикл [duplicate]

Как и другие люди, вам нужно сделать:

  myDropDown.Items.Remove (ListItem li);   

, но если вы хотите, чтобы страница обновлялась асинхронно, выпадающее меню должно быть внутри asp: UpdatePanel

после того, как вы Удалить вызов , вам нужно позвонить:

  yourPanel.Update ();   
55
задан Arpit Khandelwal 25 February 2011 в 15:41
поделиться

6 ответов

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

public static class ExtensionMethods
{
    public static int Remove<T>(
        this ObservableCollection<T> coll, Func<T, bool> condition)
    {
        var itemsToRemove = coll.Where(condition).ToList();

        foreach (var itemToRemove in itemsToRemove)
        {
            coll.Remove(itemToRemove);
        }

        return itemsToRemove.Count;
    }
}

Это удаляет все элементы из ObservableCollection, которые соответствуют условию. Вы можете так называть:

var c = new ObservableCollection<SelectableItem>();
c.Remove(x => x.IsSelected);
79
ответ дан Daniel Hilgarth 17 August 2018 в 11:58
поделиться
  • 1
    Будет ли необходимо добавить itemsToRemove.Clear () перед возвратом? – JoanComasFdz 17 August 2012 в 11:00
  • 2
    @JoanComasFdz: Нет. itemstoRemove будет востребован сборщиком мусора. – Daniel Hilgarth 17 August 2012 в 11:02
  • 3
    @ShaktiPrakashSingh: Хорошие моменты. Возврат коллекции указывает на то, что исходный текст не изменился и был создан новый. Как вы отмечаете, это не так. Кроме того, метод на List<T> возвращает счет, поэтому было бы неплохо соответствовать этому. Я изменил свой ответ соответственно. Спасибо за ваши комментарии. – Daniel Hilgarth 5 July 2013 в 11:59
  • 4
    @ DanielHilgarth Большое спасибо, ты сделал мой день! – Nicolas Bodin-Ripert 12 July 2017 в 13:54

Итерация назад должна быть более эффективной, чем создание временной коллекции, как в примере Даниэля Хильгарта.

public static class ObservableCollectionExtensions
{
    public static void RemoveAll<T>(this ObservableCollection<T> collection,
                                                       Func<T, bool> condition)
    {
        for (int i = collection.Count - 1; i >= 0; i--)
        {
            if (condition(collection[i]))
            {
                collection.RemoveAt(i);
            }
        }
    }
}
34
ответ дан guams 17 August 2018 в 11:58
поделиться
  • 1
    В тестировании реального мира я обнаружил, что это действительно быстрее, чем временная коллекция - среднее время 44 мс и пиковое 62 мс против коллекции темпа со средним временем 55 мс и пиком 93 мс – danio 18 January 2016 в 16:44

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

Если вы используете решение из Daniel Hilgarth и звоните: c.Remove(x => x.IsSelected); и, например, 3000 предметов, которые нужно удалить, предлагаемое решение сообщит об удалении каждого элемента. Это связано с тем, что внутренняя реализация Remove(item) уведомляет об этом изменении. И это будет вызвано для каждого из 3000 элементов в процессе удаления.

Поэтому вместо этого я создал потомка ObservableCollection и добавил новый метод RemoveAll(predicate)

[Serializable]
public class ObservableCollectionExt<T> : ObservableCollection<T>
{
    public void RemoveAll(Predicate<T> predicate)
    {
        CheckReentrancy();

        List<T> itemsToRemove = Items.Where(x => predicate(x)).ToList();
        itemsToRemove.ForEach(item => Items.Remove(item));

        OnPropertyChanged(new PropertyChangedEventArgs("Count"));
        OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}

Интересная строка itemsToRemove.ForEach(item => Items.Remove(item));. Вызов напрямую Items.Remove(item) не будет уведомлять об удалении элемента.

Вместо этого после удаления необходимых элементов изменения сообщаются сразу по вызовам:

OnPropertyChanged(new PropertyChangedEventArgs("Count"));
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
7
ответ дан psulek 17 August 2018 в 11:58
поделиться
  • 1
    WPF Примечание. При использовании этого элемента ItemsControl элемент управления будет вызывать Clear внутри, используя NotifyCollectionChangedAction.Reset; это привело к нежелательным побочным эффектам в моем конкретном случае использования, когда у меня были анимации на вновь добавленных элементах ~ referencesource.microsoft.com/PresentationFramework/R/… – cookbr 23 April 2015 в 14:37
  • 2
    В тестировании реального мира я обнаружил, что это было на самом деле медленнее, чем коллекция temp - среднее время 67 мс и пиковое 152 мс против коллекции temp со средним временем 55 мс и пиком 93 мс. Помните, что это было только для небольшой коллекции. – danio 18 January 2016 в 16:44

Как насчет этой реализации для одного слоя?

observableCollection.Where(l => l.type == invalid).ToList().All(i => observableCollection.Remove(i))

- Изменить -

К сожалению, вам нужен ToList () в середине, чтобы заставить первая половина для оценки, поскольку LINQ делает ленивую оценку по умолчанию.

12
ответ дан simonalexander2005 17 August 2018 в 11:58
поделиться
  • 1
    я попробовал это, но в итоге оказался с ошибкой: «Коллекция была изменена; операция перечисления может не выполняться. & quot; – usefulBee 13 November 2015 в 23:08
  • 2
    обновлено с исправлением :) – simonalexander2005 16 November 2015 в 11:22
  • 3
    Это работает после исправления. Спасибо. – usefulBee 16 November 2015 в 20:23
  • 4
    – Shimeon 10 May 2016 в 21:03
  • 5
    возможно, читабельность. Непонятно сначала прочитать, что он делает, тогда как принятый ответ разбивает его на две более очевидные части. – simonalexander2005 11 May 2016 в 09:57

Это моя версия решения метода расширения, которое является лишь небольшим изменением принятого ответа, но имеет то преимущество, что возвращенный счет основан на подтвержденном удалении элемента из коллекции :

public static class ObservableCollectionExtensionMethods
{
    /// <summary>
    /// Extends ObservableCollection adding a RemoveAll method to remove elements based on a boolean condition function
    /// </summary>
    /// <typeparam name="T">The type contained by the collection</typeparam>
    /// <param name="observableCollection">The ObservableCollection</param>
    /// <param name="condition">A function that evaluates to true for elements that should be removed</param>
    /// <returns>The number of elements removed</returns>
    public static int RemoveAll<T>(this ObservableCollection<T> observableCollection, Func<T, bool> condition)
    {
        // Find all elements satisfying the condition, i.e. that will be removed
        var toRemove = observableCollection
            .Where(condition)
            .ToList();

        // Remove the elements from the original collection, using the Count method to iterate through the list, 
        // incrementing the count whenever there's a successful removal
        return toRemove.Count(observableCollection.Remove);
    }
}
0
ответ дан Chris Peacock 17 August 2018 в 11:58
поделиться
0
ответ дан jjrdk 17 August 2018 в 11:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: