2012-04-16 12 views
7

Abbiamo una funzione cronologica del nostro software. Mostra righe di piccoli blob che indicano i dati in diversi punti del tempo. Il codice è C#, .Net 4 e WPF. Per mostrare un blob, stiamo attualmente creando un bordo (dandogli un pennello) e aggiungendolo a una griglia. Questa griglia viene quindi aggiunta a una griglia padre che forma le righe.Come mostrare in modo efficiente la grafica in WPF?

Questo va bene quando la linea temporale mostra numeri relativamente piccoli di blob, ma quando i dati sono molto occupati, il rendering rallenta, l'utilizzo di mem aumenta e l'interfaccia utente non risponde. (Non a caso).

So che non stiamo facendo questo nel modo migliore - la mia domanda è qual è il modo migliore per visualizzare grafici come questo in wpf?

MODIFICA: Grazie per le risposte riportate di seguito - esaminerò queste opzioni. Tuttavia ognuno richiede una grande quantità di ricodifica e la mia domanda qui è più semplice; C'è qualche controllo o effetto che posso usare per sostituire Border, che è un costo di risorse inferiore?

+0

Non si dovrebbero creare elementi in modo programmatico e aggiungerli alla griglia in questo modo. È necessario creare un datatemplate listItem per i BLOB e quindi associare una raccolta di BLOB a un listView. – Alain

+0

Sarebbe molto difficile ottenere uno scorrimento fluido in questo modo, no? Dovrei aggiungere tutti i dati alla raccolta (che si arresterebbero in modo anomalo) o ripopolare in modo dinamico la raccolta, che probabilmente non sembrerebbe liscia. – Sugrue

risposta

4

Per la visualizzazione di dati come questa mi piace molto DynamicDataDisplay. Il componente è attualmente mantenuto/sviluppato solo per Silverlight ma esiste una versione open source (in collegamento) per WPF che è davvero una grande libreria.

La libreria utilizza le raccolte IObservable e supporta i valori degli assi DateTime.

C'è un tipo di grafico marker incorporato (esempio sotto).

È possibile utilizzare marcatori personalizzati, supporta lo zoom e lo scorrimento, molte altre funzioni interessanti, ecc. È anche molto veloce, anche con serie di dati piuttosto grandi.

Poiché i set di dati sono IObservable, il componente del grafico risponde dinamicamente alle modifiche nel set di dati sottostante in modo che il grafico venga aggiornato ogni volta che la raccolta di dati viene aggiornata.

EDIT

Ecco un esempio:

utilizza:

using System.ComponentModel; 
using Microsoft.Research.DynamicDataDisplay; 
using Microsoft.Research.DynamicDataDisplay.Charts; 
using Microsoft.Research.DynamicDataDisplay.DataSources; 
using Microsoft.Research.DynamicDataDisplay.PointMarkers; 

principale:

public Window1() 
    { 
     InitializeComponent(); 
     // 
     const int N = 100; 
     List<double> x = new List<double>(); 
     List<double> y = new List<double>(); 

     DateTimeAxis dtAxis = new DateTimeAxis(); 
     _plotter.HorizontalAxis = dtAxis; 

     Random rand = new Random(); 
     for (int i = 0; i < N; i++) 
     { //generate some random data 
      x.Add(dtAxis.ConvertToDouble(DateTime.Now.AddDays(i))); 
      y.Add(rand.Next(N)); 
     } 

     EnumerableDataSource<double> gX = new EnumerableDataSource<double>(x); 
     EnumerableDataSource<double> gY = new EnumerableDataSource<double>(y); 
     _MarkerGraph.DataSource = new CompositeDataSource(gX,gY); 

     //no scaling - identity mapping 
     gX.XMapping = xx => xx; 
     gY.YMapping = yy => yy; 

     CirclePointMarker mkr = new CirclePointMarker(); 
     mkr.Fill = new SolidColorBrush(Colors.Red); 
     mkr.Pen = new Pen(new SolidColorBrush(Colors.Black),2.0); 
     _MarkerGraph.Marker = mkr; 
    } 

XAML:

<Window x:Class="WpfApplication1.Window1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:d3="clr-namespace:Microsoft.Research.DynamicDataDisplay;assembly=DynamicDataDisplay" 
Title="Window1" Height="481" Width="651"> 
<Grid> 
    <d3:ChartPlotter Name="_plotter"> 
     <d3:MarkerPointsGraph Name="_MarkerGraph"/> 
    </d3:ChartPlotter> 
</Grid> 

uscita: Program runs...

Le scale degli assi DateTime splendidamente, regolando le zecche per giorni, mesi, ore, secondi ... tutto ciò che è appropriato. Facile come torta!

Se si utilizza questo pacchetto, I altamente consiglia di scaricare l'origine e aggiungerlo come secondo progetto alla soluzione. La documentazione è molto scarsa per D3 e avere la fonte nel progetto è utile per capire come funzionano le cose. Rende anche molto facile aggiungere/estendere le cose se necessario.Assicurati di fare riferimento al progetto in-solution se lo fai e non la DLL compilata.

Si noti inoltre che molta della documentazione disponibile e degli esempi online sono destinati al componente Silverlight gestito e non al componente WPF aperto. Molti dei componenti sono diversi tra queste due versioni, quindi è necessario scavare attraverso il componente WPF per vedere cosa c'è. L'esempio sopra è per il componente WPF v0.3.

+0

Grazie per quello. Interessante, e potrei usarlo un giorno. Preferirei non dover ricodificare radicalmente il nostro sistema attuale. Funziona al 99%, mi piacerebbe solo rendere il rendering effettivamente più efficiente. – Sugrue

+0

@Sugrue Penso che per rendere il rendering più efficiente, probabilmente dovrai comunque cambiare approccio. Probabilmente sarà necessario disegnare tutti i tuoi elementi su una singola tela per ottenere le prestazioni desiderate e questo è un allontanamento dall'approccio grid-in-grid che stai utilizzando. Finché i tuoi dati sono già risolti, in realtà è molto veloce semplicemente inserire un componente grafico e collegarlo insieme. –

+0

@Sugrue: aggiunto un esempio per mostrare quanto sia facile! In realtà, questo componente è solo un motore di rendering dei dati molto efficiente, che è esattamente il problema che stai cercando di risolvere. A parte poche righe per convertire i dati, dovrebbe essere una soluzione per lo più drop-in. –

3

Se si desidera disegnare molte immagini in continua evoluzione, il modo più veloce che WPF deve offrire è quello di sovrascrivere OnRender e disegnare nel DrawingContext.

Se le immagini sono per lo più statiche, ma a volte possono cambiare, il modo più veloce è creare uno DrawingVisual per ciascuna, che può quindi essere modificato in base alle esigenze.

Ulteriori dettagli in this question, l'articolo collegato e le risposte.

+0

Grazie, lo indagherò. – Sugrue

Problemi correlati