net - para que sirve observablecollection c#
Agregar un rango de valores a una ObservableCollection de manera eficiente (4)
Tengo una ObservableCollection
de elementos que está vinculada a un control de lista en mi opinión.
Tengo una situación en la que necesito agregar una parte de los valores al inicio de la colección. Collection<T>.Insert
especifica cada inserción como una operación O (n), y cada inserción también genera una notificación de CollectionChanged
.
Por lo tanto, lo ideal sería insertar todo el rango de elementos en un solo movimiento, es decir, solo un orden aleatorio de la lista subyacente y, con suerte, una notificación CollectionChanged
(probablemente un "restablecimiento").
Collection<T>
no expone ningún método para hacer esto. List<T>
tiene InsertRange()
, pero IList<T>
, que la Collection<T>
expone a través de su propiedad Items
no.
¿Hay alguna forma de hacer esto?
Ejemplo: pasos deseados 0,10,20,30,40,50,60,70,80,90,100,00 -> min = 0, max = 100, pasos = 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())
);
Esta answer no me mostró las nuevas entradas en un DataGrid. Este OnCollectionChanged funciona para mí:
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[]"));
}
}
ObservableCollection expone una propiedad de Items
protegidos que es la colección subyacente sin la semántica de notificación. Esto significa que puede crear una colección que haga lo que quiere al heredar ObservableCollection:
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));
}
}
Uso:
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);
}
Para hacer que la respuesta anterior sea útil sin derivar una nueva clase base mediante la reflexión, he aquí un ejemplo:
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)});
}