In Silverlight, come popolare un DataGrid ordinato da una connessione che cambia dinamicamente

StackOverflow https://stackoverflow.com/questions/234424

  •  04-07-2019
  •  | 
  •  

Domanda

Ho un set di dati i cui elementi sono visualizzati come righe in un DataGrid. L'ordinamento per le righe cambia in risposta a eventi esterni.

Il mio pensiero iniziale era di archiviare le righe come ObservableCollection e ricorrere alla raccolta dopo gli aggiornamenti. Tuttavia ho riscontrato due problemi: 1) ObservableCollection non ha un metodo Sort () 2) se provo a ordinare gli elementi da solo, ottengo un'eccezione ogni volta che provo ad assegnare un elemento a una nuova posizione, ad esempio in una funzione di scambio come

class MyCollection : ObservableCollection<T>
{
   void swap( int i, int j )
   {
      T tmp = this[i];
      this[i] = this[j]; // THROWS A NOT SUPPORTED EXCEPTION
      this[j] = tmp;
   }
}

Quindi la domanda è ... come popolare un DataGrid il cui ordine di riga deve essere aggiornato in modo dinamico?

Finalmente ho ottenuto una risposta funzionante, la descriverò di seguito.

È stato utile?

Soluzione

L'ho fatto funzionare implementando INotifyCollectionChanged esplicitamente (invece di usare ObservableCollection). Inoltre, ho scoperto che l'utilizzo dell'azione di aggiornamento ha prodotto lo stesso "non supportato" errore, ma che avrei potuto usare le azioni Aggiungi e Rimuovi. Quindi la mia funzione di swap si presenta così:

class MyCollection<T> : List<T>, INotifyCollectionChanged
{
   public event NotifyCollectionChangedEventHandler CollectionChanged;

   private void swap( int i, int j )
   {
      T a = this[i];
      T b = this[j];

      // swap my own internal data storage
      this[i] = b;
      this[j] = a;

      // and also let my CollectionChanged listener know that I have done so.
      if( CollectionChanged != null )
      {
         NotifyCollectionChangedEventArgs arg;

         arg = new NotifyCollectionChangedEventArgs(
             NotifyCollectionChangedAction.Remove, a, i );
         CollectionChanged( this, arg );

         arg = new NotifyCollectionChangedEventArgs(
             NotifyCollectionChangedAction.Add, b, i );
         CollectionChanged( this, arg );

         arg = new NotifyCollectionChangedEventArgs(
             NotifyCollectionChangedAction.Remove, b, j );
         CollectionChanged( this, arg );

         arg = new NotifyCollectionChangedEventArgs(
             NotifyCollectionChangedAction.Add, a, j );
         CollectionChanged( this, arg );

      }

   }

}

Le modifiche dinamiche sono abbastanza locali, quindi fortunatamente usare un ordinamento scritto a mano più lento in risposta alle modifiche funziona bene per me. In altre parole, quando arrivano gli aggiornamenti, invoco un'altra funzione membro (nella stessa raccolta) che assomigli a questo:

public void ProcessUpdates( List<T> updateList )
{
    // use the contents of updateList to modify my internal store
    // ...


    // and now resort myself
    sort();
}

private void sort()
{
    // implement your favorite stable sorting algorithm here, calling 
    // swap() whenever you swap two elements.

    // (this is an intentionally facetious sorting algorithm, because I
    // don't want to get into the long and irrelevant details of my own 
    // data storage.)
    while( i_am_not_sorted() )
    {
       int i = random_index();
       int j = random_index();
       if( out_of_order(i,j) )
       {
          // modify my internal data structure and 
          // also let my CollectionChanged listener know that I have done so
          swap( i, j );
       }
    }
}

Non dimenticare che è anche necessario attivare un " Aggiungi " notifica quando si aggiungono elementi alla raccolta! Ordino l'elenco iniziale e quindi aggiungo in ordine, che mi consente di utilizzare un ordinamento di libreria più efficiente quando popolo per la prima volta i dati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top