web-dev-qa-db-ja.com

ObservableCollectionsのRemoveAll?

ObservableCollectionから選択したアイテムを削除できるLinqの方法(ListのRemoveAllメソッドなど)を探しています。

私は自分自身の拡張メソッドを作成するにはあまりにも新しいです。 Lambda式を渡すObservableCollectionからアイテムを削除する方法はありますか?

67

選択したアイテムのみを削除する方法を知りません。ただし、拡張メソッドの作成は簡単です。

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);
91
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);
            }
        }
    }
}
39
guams

ワンライナーのこの実装はどうですか?

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

-編集-

申し訳ありませんが、デフォルトではLINQは遅延評価を行うため、前半の評価を強制するには、中間にToList()が必要です。

13

ルーチンを使用してアイテムを1つずつ削除する、ここで提案するソリューションにはそれぞれ1つの障害があります。観察可能なコレクションに多くのアイテムがあると想像してください。たとえば、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));
_
9
psulek

これは、拡張メソッドソリューションの私のバージョンです。これは、受け入れられた回答のわずかなバリエーションにすぎませんが、返されるカウントがコレクションからのアイテムの確認済み削除に基づいているという利点があります。

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);
    }
}
1
Chris Peacock
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);
}
1
user10860989

ジェネリックリストと同じように、一致するアイテムを削除する式をObservableCollectionに渡す方法はありません。 ObservableCollectionは、一度に1つのアイテムを追加および削除します。

これを行うには、または前述のように拡張メソッドを作成するために、独自のINotifyCollectionChangedの実装を作成する必要があります。

1
jjrdk