c# wpf graphics graph vector-graphics

c# - path wpf



Cómo dibujar gráficos de la manera más eficiente posible en WPF (3)

Estoy creando una herramienta que se basa en gran medida en los árboles de nodos gráficos. La implementación actual se realiza en Java y la estoy transfiriendo a una base de código genérica en C #, por lo que puede ser utilizada por varias implementaciones de representación y también porque quiero usar el poder de WPF para una interfaz fácil de usar.

Después de navegar por un día, encontré varios métodos para dibujar gráficos vectoriales a través de WPF.

Este tipo habla sobre las diferentes capas dentro de las que los desarrolladores de WPF pueden elegir. Como quiero usar WPF PURAMENTE para su renderizado al principio, quiero trabajar en la "Capa Visual".

Luego encontré cosas como: DrawingVisual , GeometryDrawing , FrameworkElement / UIElement / Shapes

Por lo tanto, estoy un poco abrumado por todas las diferentes implementaciones que eventualmente hacen lo mismo de maneras totalmente diferentes.

La biblioteca Graph-Node se ha portado a C # ya con toda su lógica (incluida la detección de colisiones y el arrastre con el mouse). Como está hecho con los renderizadores gráficos en mente (como XNA, SlimDX, OpenTK, etc.), cuál sería la mejor manera en términos de rendimiento para implementar un renderizador WPF (como en, dibujará lo que diga la biblioteca de gráficos) ¿dibujar?

Básicamente, el control WPF resultante actúa como un lienzo, pero tiene que ser SUPER LIGERO y no tener ninguna característica clara de WPF, además de proporcionarme una forma de dibujar mis círculos, líneas y otras formas :)

EDITAR:

Básicamente quiero saber: ¿Cuál es el camino a seguir? ¿Extiendo Canvas como "Host" para mis gráficos y luego agrego mi implementación personalizada de un UIElement? O puedo tener una clase que pueda dibujar TODO (como en un mega super ultra gráfico). Al igual que anular OnPaint en GDI o Paint-method en Java (lo que le da a un objeto de Gráficos para hacer todo con).


El DrawingVisual parece ser una opción válida:

DrawingVisual es una clase de dibujo ligero que se utiliza para representar formas, imágenes o texto. Esta clase se considera liviana porque no proporciona diseño o manejo de eventos, lo que mejora su rendimiento. Por esta razón, los dibujos son ideales para fondos y clip art.

fuente: Uso de objetos de DrawingVisual

Así que esto parece ser absolutamente lo que pides, un Canvas SUPER liviano.


En general, se obtiene un mejor rendimiento con servicios de nivel inferior. En WPF , esto significa la familia de objetos Drawing . Todo lo que obtienes son: Drawing , DrawingGroup , GeometryDrawing , GlyphRunDrawing , ImageDrawing y VideoDrawing . Sin embargo, son suficientes para todas las necesidades. El uso de estos tipos es muy fácil con WPF porque Drawing es la unidad conceptual que WPF intercambia con su acelerador de GPU, posiblemente reteniéndolo y administrándolo allí si es posible. Esto funciona porque el Drawing se expresa en términos de primitivas de dibujo vectorial portátil.

Sin embargo, una vez que comience a rediseñar su aplicación alrededor de Drawings , es posible que necesite un poco de interoperabilidad con su código de nivel superior, que aún se basa en UIElement , FrameworkElement , etc. forma de envolver un dibujo como FrameworkElement de la manera más baja posible. DrawingVisual no es una solución completa, porque solo se deriva de Visual significa que todavía requiere un elemento de alojamiento.

La siguiente clase alojará cualquier Drawing WPF directamente sin usar un DrawingVisual intermedio. Agregué soporte para la propiedad Margin FrameworkElement (sin penalización de rendimiento si no se usa) pero poco más. Debido al único subproceso de representación de WPF, es seguro y fácil almacenar en caché un único objeto TranslateTransform para implementar el margen. Recomiendo que proporcione solo dibujos que hayan sido congelados; de hecho, en la versión que uso, tengo una aserción a ese efecto en el constructor.

public class DrawingElement : FrameworkElement { static readonly TranslateTransform tt_cache = new TranslateTransform(); public DrawingElement(Drawing drawing) { this.drawing = drawing; } readonly Drawing drawing; TranslateTransform get_transform() { if (Margin.Left == 0 && Margin.Top == 0) return null; tt_cache.X = Margin.Left; tt_cache.Y = Margin.Top; return tt_cache; } protected override Size MeasureOverride(Size _) { var sz = drawing.Bounds.Size; return new Size { Width = sz.Width + Margin.Left + Margin.Right, Height = sz.Height + Margin.Top + Margin.Bottom, }; } protected override void OnRender(DrawingContext dc) { var tt = get_transform(); if (tt != null) dc.PushTransform(tt); dc.DrawDrawing(drawing); if (tt != null) dc.Pop(); } };

[edit:] Esto también es útil para insertar un Drawing WPF en la propiedad InlineUIContainer.Child (es decir, usar TextBlock.InlinesCollection para dar formato al contenido de TextBlock de manera más rica).