2011-12-22 19 views
26

Görünümümde bir liste denetimine bağlı olan ObservableCollection öğem var.Bir Gözlemlenebilir Çok Noktaya verimli bir değer aralığı ekleme

Koleksiyonun başlangıcına bir değer kümesini eklemem gereken bir durumum var. Collection<T>.Insert belgeleri her eki bir O (n) işlemi olarak belirtir ve her bir ek de CollectionChanged bildirimi oluşturur.

Bu nedenle, tüm öğeleri tek bir hareketle eklemek istiyorum, yani temel listenin yalnızca bir karması ve umarım bir CollectionChanged bildirimi (muhtemelen bir "sıfırlama"). Bunu yapmak için herhangi bir yöntem göstermez.

Collection<T>. List<T>'un InsertRange(), ancak , Collection<T>, Items özelliği aracılığıyla gösterilmez.

Bunu yapmanın herhangi bir yolu var mı?

+0

- buna yeni bir örneğini atayabilir ve daha sonra toplama mülkünüze için 'OnPropertyChanged' yükseltmek elle – sll

+1

ilgili/olası yinelenen http: // 'GözlemlenebilirKoleksiyon' kuantum mekaniği ve çift yarık deneyi hakkında düşünmenizi sağlıyorsa stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each – Adam

+2

+1. – rfmodulator

cevap

50

ObservableCollection, bildirim semantiği olmadan temeldeki koleksiyon olan korumalı bir Items özelliğini gösterir. Bu miras ObservableCollection tarafından ne istediğini yaptığı bir koleksiyonu oluşturmak anlamına gelir:

class RangeEnabledObservableCollection<T> : ObservableCollection<T> 
{ 
    public void InsertRange(IEnumerable<T> items) 
    { 
     this.CheckReentrancy(); 
     foreach(var item in items) 
      this.Items.Add(item); 
     this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 
} 

Kullanımı:

void Main() 
{ 
    var collection = new RangeEnabledObservableCollection<int>(); 
    collection.CollectionChanged += (s,e) => Console.WriteLine("Collection changed"); 
    collection.InsertRange(Enumerable.Range(0,100)); 
    Console.WriteLine("Collection contains {0} items.", collection.Count); 
} 
+6

Diğer [yanıt] (http://stackoverflow.com/questions/13302933/how saymak ve indeksleyici özellikleri değişiklikleri bildirmek için aşağıdaki kodu eklemek için önerilen benzer bir soru için-önlemek-ateş-gözlenebilir-collablecollection-collectionchanged-multiple-times-when-r): 'this.OnPropertyChanged (new PropertyChangedEventArgs (" Count "))); ' ' this.OnPropertyChanged (yeni PropertyChangedEventArgs ("Öğe []")); – bouvierr

7

Yukarıdaki yanıtın yararlı hale getirmek için yansıma kullanarak yeni bir temel sınıf türetmek o burada w/bir örnek:

public static void InsertRange<T>(this ObservableCollection<T> collection, IEnumerable<T> items) 
{ 
    var enumerable = items as List<T> ?? items.ToList(); 
    if (collection == null || items == null || !enumerable.Any()) 
    { 
    return; 
    } 

    Type type = collection.GetType(); 

    type.InvokeMember("CheckReentrancy", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, collection, null); 
    var itemsProp = type.BaseType.GetProperty("Items", BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance); 
    var privateItems = itemsProp.GetValue(collection) as IList<T>; 
    foreach (var item in enumerable) 
    { 
    privateItems.Add(item); 
    } 

    type.InvokeMember("OnPropertyChanged", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, 
    collection, new object[] { new PropertyChangedEventArgs("Count") }); 

    type.InvokeMember("OnPropertyChanged", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, 
    collection, new object[] { new PropertyChangedEventArgs("Item[]") }); 

    type.InvokeMember("OnCollectionChanged", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, 
    collection, new object[]{ new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)}); 
} 
+1

Kalıcılık ile ilgili sorun nedir? Neden yeni bir sınıf türetmek yerine yansıma kullanarak kullanıyorsunuz? – ventiseis

+3

Elbette mirasta yanlış bir şey yok. Bu sadece bunun bir alternatifi. Bir ton eski kodunuz varsa ve serileştirmeniz (ikili) bir ObservableCollection türüne bağlıysa yararlı olabilir. Bu durumda sadece ObservableCollection'ı genişletmek için daha kolay ve çok daha pragmatik bir seçim. – outbred

+0

Merhaba @outbred. Üzgünüm, örneğini nasıl kullanıyorsun?Teşekkürler – NevilleDastur

-2

Örnek: İstenen adımları 0,10,20,30,40,50,60,70,80,90,100 -> min = 0, maks = 100, adım = 11

static int min = 0; 
    static int max = 100; 
    static int steps = 11; 

    private ObservableCollection<string> restartDelayTimeList = new ObservableCollection<string> (
     Enumerable.Range(0, steps).Select(l1 => (min + (max - min) * ((double)l1/(steps - 1))).ToString()) 
    ); 
3

Bu answer bana bir DataGrid'deki yeni girdileri göstermedi. Bu benim için işleri OnCollectionChanged: Eğer toplama özelliği için bir destek alanı varsa

public class SilentObservableCollection<T> : ObservableCollection<T> 
{ 
    public void AddRange(IEnumerable<T> enumerable) 
    { 
     CheckReentrancy(); 

     int startIndex = Count; 

     foreach (var item in enumerable) 
      Items.Add(item); 

     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<T>(enumerable), startIndex)); 
     OnPropertyChanged(new PropertyChangedEventArgs("Count")); 
     OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); 
    } 
} 
+0

Bunlar, daha uygun değişiklik bildirimleri gibi görünüyor. – OttPrime

İlgili konular