2012-04-03 18 views
11

Devo disegnare un sacco di Shape (circa 1/2 centinaia di migliaia) come bambini [Canvas] [2]. Lo faccio nella mia applicazione WPF dividendo il lavoro in due parti: per prima cosa creo le forme impostando le proprietà di ciascuna di esse (come Margine, Riempimento, Larghezza, ecc.), Dopo aver aggiunto forme come i figli di Canvas.Come migliorare le prestazioni di rendering della tela?

MyCanvas.Children.Add(MyShape) 

ora voglio migliorare le prestazioni della seconda parte, perché quando disegno le forme la mia domanda è bloccato per un lungo periodo di tempo. Così ho provato a usare lo Dispatcher e il suo metodo [BeginInvoke] [4] con diverse [priorità] [5]: solo se uso la priorità Sfondo l'applicazione principale non si blocca, altrimenti l'applicazione rimane bloccata e la "immagine" è non viene visualizzato finché tutte le forme non sono state aggiunte alla tela, ma se utilizzo la priorità Sfondo ovviamente tutto è più lento. Ho anche provato a creare un nuovo thread invece di usare Dispatcher, ma non ci sono stati cambiamenti significativi.

Come posso risolvere questo problema e, in generale, migliorare le prestazioni della mia applicazione quando aggiungo le mie forme a Canvas?

Grazie.

+0

Hai provato DrawingVisual? –

+0

No. Potresti darmi un esempio di come usare DrawingVisual invece di una Shape come Ellisse o Path. Ad esempio, come posso aggiungere al percorso Canvas [this] (http://msdn.microsoft.com/en-us/library/ms745546.aspx) Path using DrawingVisual? – gliderkite

+0

Sì, ci sono alcune ottime informazioni su google. Ecco un link per iniziare: http://msdn.microsoft.com/en-us/magazine/dd483292.aspx –

risposta

7

È necessario utilizzare gli oggetti Visual anziché Shape; in particolare, come suggerito, DrawingVisual: un oggetto visivo che può essere utilizzato per il rendering di grafica vettoriale. Infatti, come scritto nella libreria MSDN:

DrawingVisual è una classe di disegno leggera che viene utilizzata per il rendering di forme, immagini o testo. Questa classe è considerata leggera perché non fornisce layout, input, focus o gestione degli eventi, il che migliora le sue prestazioni. Per questo motivo, i disegni sono ideali per gli sfondi e le clip art.

Così, ad esempio, per creare un DrawingVisual che contiene un rettangolo:

private DrawingVisual CreateDrawingVisualRectangle() 
{ 
    DrawingVisual drawingVisual = new DrawingVisual(); 

    // Retrieve the DrawingContext in order to create new drawing content. 
    DrawingContext drawingContext = drawingVisual.RenderOpen(); 

    // Create a rectangle and draw it in the DrawingContext. 
    Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80)); 
    drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect); 

    // Persist the drawing content. 
    drawingContext.Close(); 

    return drawingVisual; 
} 

Per poter utilizzare gli oggetti DrawingVisual, è necessario creare un contenitore host per gli oggetti. L'oggetto contenitore host deve derivare dalla classe FrameworkElement, che fornisce il supporto per il layout e la gestione degli eventi a cui manca la classe DrawingVisual. Quando si crea un oggetto contenitore host per oggetti visivi, è necessario memorizzare i riferimenti all'oggetto visivo in un VisualCollection.

public class MyVisualHost : FrameworkElement 
{ 
    // Create a collection of child visual objects. 
    private VisualCollection _children; 

    public MyVisualHost() 
    { 
     _children = new VisualCollection(this); 
     _children.Add(CreateDrawingVisualRectangle()); 

     // Add the event handler for MouseLeftButtonUp. 
     this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MyVisualHost_MouseLeftButtonUp); 
    } 
} 

L'evento routine di gestione può quindi implementare test colpito richiamando il metodo HitTest. Il parametro HitTestResultCallback del metodo fa riferimento a una procedura definita dall'utente che è possibile utilizzare per determinare l'azione risultante di un hit test.

+3

Aiuterà, marginalmente, comunque WPF non è progettato per gestire 50.000 immagini di qualsiasi tipo. –

+0

Quindi cosa è adatto per gestire centinaia di elementi grafici vettoriali? – gliderkite

+0

Vedere la sezione Q e AI collegata a: http://stackoverflow.com/questions/8713864/grafico-performance-uso-il-piccolo-wpf-visual-layer/8714107#8714107 –

1

Questo è molto di UIElements e probabilmente non offrirà il tipo di prestazione che stai cercando. Devi essere in grado di interagire con ciascuno degli elementi che stai rendendo? In caso contrario, consiglio vivamente di utilizzare WriteableBitmap. Se hai bisogno di disegnare forme e non vuoi creare tutta questa logica da solo (chi vorrebbe?), check out the WriteableBitmapEx project over on CodePlex.

+0

Ho bisogno di interagire con tutte le forme, inoltre uso Shape perché la "immagine" è un'immagine grafica vettoriale (l'immagine può essere ridimensionata - con lo zoom - di qualsiasi valore senza qualità degradante). Con WritableBitmapEx potrei fare le stesse cose? – gliderkite

+1

Non userei Shape, userei DrawingVisual. Puoi aggiungere questi dettagli alla tua domanda per favore? Ci penserò e rivedere la mia risposta. –

3

Concorda sul fatto che se si desidera disegnare milioni di elementi, semplicemente non è possibile farlo in WPF. WriteableBitmapEx come accennato è una buona alternativa.

Vedere this related question che approfondisce la grafica ad alte prestazioni in WPF e le alternative disponibili.

Se devi semplicemente utilizzare Canvas, controlla questo ZoomableApplication2 - A million items. Questa è una demo basata su Canvas che fa un uso pesante della virtualizzazione per ottenere prestazioni ragionevoli con 1.000.000 UIElements su una tela.

+0

è possibile perché devo disegnare circa 1/2 centinaia di migliaia di elementi (come ho scritto) e ho usato la mia risposta (è passato molto tempo da quando ho fatto la domanda), comunque grazie per la tua risposta, ma bitmap non è una grafica vettoriale. – gliderkite

1

Questo potrebbe essere in qualche modo non correlato, e mi scuso se ti senti in questo modo, ma nella speranza che possa far luce per altri utenti, condividerò questo bocconcino.

Abbiamo riscontrato alcuni problemi di prestazioni con un controllo Canvas utilizzato per l'acquisizione delle firme. La cattura era molto frastagliata e non potevamo disegnare linee curve come risultato. È risultato essere relativo a uno stile stava generando le ombre sull'elemento dell'interfaccia utente. Disabilitare l'effetto drop-shadow ha risolto il nostro problema.

+0

Grazie a ciò, stavo riscontrando problemi di prestazioni che disegnavano un gran numero di linee su una griglia e rimuovendo il mio effetto ombra non c'è lag a tutti! – Cyral

Problemi correlati