c# - que - uwp observablecollection class




WPF DataGrid agrega una fila adicional "fantasma" (2)

Tal vez me falta algo obvio, pero la implementación de AsyncObservableCollection en el enlace que publicó no parece segura para subprocesos.

Puedo ver que incluye código para activar los eventos CollectionChanged / PropertyChanged en el hilo del creador (consumidor), pero no veo ninguna sincronización para hacer que el acceso a los elementos en la colección sea seguro para subprocesos.

ACTUALIZAR

Por lo que puedo ver, puede suceder lo siguiente simultáneamente, sin ninguna sincronización:

  • el hilo del trabajador (productor) está insertando artículo (s)

  • el subproceso de UI (consumidor) está enumerando elementos

Una posibilidad podría ser modificar AsyncObservableCollection.InsertItem para llamar a SynchronizationContext.Send para insertar el elemento en el hilo del consumidor, aunque esto tendrá un efecto en el rendimiento (el productor espera a que el hilo del consumidor complete la inserción antes de continuar).

Un enfoque alternativo sería usar un ObservableCollection estándar al que solo se accede en el hilo del consumidor, y usar SynchronizationContext.Post para publicar elementos para insertar desde el hilo del productor. Algo como:

foreach (var dirFile in dirFiles.AsParallel())
{
    var order = new Order(dirFile, this, convention);

    _synchronizationContext.Post(AddItem, order);

}

...

void AddItem(object item)
{
    // this is executed on the consumer thread
    // All access to OrderCollection on this thread so no need for synchnonization
    Order order = (Order) item;
    if (!OrdersCollection.ContainsOrder(order))
    {
        OrdersCollection.Add(order);
    }
}

Hei,

En mi aplicación estoy usando DataGrid para mostrar algunos datos. Para que todo funcione con Threading estoy usando AsyncObservableCollection como DataContext de DataGrid. Cuando se inicia mi aplicación, busca archivos en algunas carpetas y actualiza AsyncObservableCollection . Encontrar archivos se hace en un hilo separado:

Task.Factory.StartNew(() => _cardType.InitAllOrdersCollection())
    .ContinueWith((t) => ThrowEvent(), TaskContinuationOptions.None);

Donde toda la lógica de carga está en el método InitAllOrdersCollection() .

Ahora aquí es donde las cosas van mal, cuando comienzo la aplicación por alguna razón, obtengo 2 filas con los mismos datos en DataGrid, incluso si hay un elemento en la colección y solo un archivo en las carpetas. Si agrego un retraso ( Thread.Sleep() 50ms mínimo) antes de cargar archivos, DataGrid mostrará todo correctamente (sin filas adicionales). El retraso debe agregarse al hilo de lo que está cargando los archivos (el creado con Task.Factory.StartNew() ).

¿Alguien ha encontrado algo similar o hay algo más que deba probar? ¡Gracias por adelantado!

EDITAR: Agregar un código según lo solicitado:

public AsyncObservableCollection<IGridItem> OrdersCollection = new AsyncObservableCollection<IGridItem>();

public void InitAllOrdersCollection()
{
    // Thread.Sleep(50); <-- this sleep here fixes the problem!
    foreach (var convention in FileNameConventions)
    {
        var namePatterns = convention.NameConvention.Split(',');
        foreach (var pattern in namePatterns)
        {
            var validFiles = CardTypeExtensions.GetFiles(this.InputFolder, pattern, convention);
            if (validFiles.Any())
            {
                this.FilesToOrders(validFiles, convention);
            }
        }
    }
}

public static List<string> GetFiles(string inputFolder, string pattern, FileNameConvention convention)
{
    var files = Directory.GetFiles(inputFolder, pattern);
    return files.Where(file => IsCorrect(file, convention)).AsParallel().ToList();
}

// Adds new order to OrdersCollection if its not there already!
private void FilesToOrders(List<string> dirFiles, FileNameConvention convention)
{
    foreach (var dirFile in dirFiles.AsParallel())
    {
        var order = new Order(dirFile, this, convention);

        if (!this.OrdersCollection.ContainsOrder(order))
        {
                this.OrdersCollection.Add(order);
        }
    }
}

public static bool ContainsOrder(this ObservableCollection<IGridItem> collection, Order order)
{
    return collection.Cast<Order>().Any(c=>c.Filepath == order.Filepath);
}

FilesToOrders() método FilesToOrders() es el que agrega las nuevas órdenes a AsyncObservableCollection . Espero que esto ayude.


Agregue CanUserAddRows="False" a su archivo XAML

<DataGrid CanUserAddRows="False"../>




observablecollection