programing

ObservableCollections에 대한 RemoveAll?

nasanasas 2020. 11. 7. 10:11
반응형

ObservableCollections에 대한 RemoveAll?


내 ObservableCollection에서 선택한 항목을 제거 할 수있는 Linq 방식 (List의 RemoveAll 메서드와 같은)을 찾고 있습니다.

나는 나 자신을위한 확장 방법을 만들기에는 너무 새롭다. Lambda 표현식을 전달하는 ObservableCollection에서 항목을 제거하는 방법이 있습니까?


선택한 항목 만 제거하는 방법을 모릅니다. 그러나 확장 메서드를 만드는 것은 간단합니다.

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

역방향 반복은 Daniel Hilgarth의 예 에서처럼 임시 컬렉션을 만드는 것보다 더 효율적이어야합니다.

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

한 줄짜리 구현은 어떻습니까?

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

-- 편집하다 --

죄송합니다. LINQ는 기본적으로 지연 평가를 수행하므로 전반부를 강제로 평가하려면 중간에 ToList ()가 필요합니다.


루틴을 사용하여 항목을 하나씩 제거하는 여기에서 제안 된 각 솔루션에는 하나의 오류가 있습니다. 관찰 가능한 컬렉션에 많은 항목이 있다고 가정 해 보겠습니다. 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));

There is no way to pass an expression to the ObservableCollection to remove matching items, in the same way that a generic list has. ObservableCollection adds and removes one item at a time.

You will have to create your own implementation of INotifyCollectionChanged in order to do this, or as you mention create an extension method.


This is my version of an extension method solution, which is only a slight variation on the accepted answer, but has the advantage that the count returned is based on confirmed removal of the item from the collection:

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

ObservableCollection<AppVariable<G>> _appVariables = new new ObservableCollection<AppVariable<G>>();

var temp = AppRepository.AppVariables.Where(i => i.IsChecked == true).OrderByDescending(k=>k.Index);

foreach (var i in temp)
{
     AppRepository.AppVariables.RemoveAt(i.Index);
}

참고URL : https://stackoverflow.com/questions/5118513/removeall-for-observablecollections

반응형