Jak jak najefektywniej rysować grafikę w WPF

Tworzę narzędzie, które w dużej mierze opiera się na drzewach węzłów wykresowych. Obecna implementacja jest wykonywana w Javie i portuję ją do ogólnego kodu bazującego na C#, więc może być używana przez różne implementacje renderowania, a także dlatego, że chcę użyć mocy WPF dla przyjaznego dla użytkownika interfejsu.

Po przejrzeniu całego dnia natknąłem się na różne metody rysowania grafiki wektorowej przez WPF.

Ten facet mówi o różnych warstwach w programistach WPF wybierz z. Ponieważ chcę używać WPF wyłącznie do jego renderowania na początku, chcę pracować nad "warstwą wizualną".

Wtedy natknąłem się na takie rzeczy jak: DrawingVisual , GeometryDrawing , Framework / UIElement / Shapes

Jestem nieco przytłoczony różnymi implementacjami, które w końcu robią to samo na zupełnie inne sposoby.

Biblioteka Graph-Node została już przeportowana do C# z całą logiką (w tym kolizją wykrywanie i przeciąganie myszką). Jak to robi się z myślą o graficznych rendererach (jak XNA, SlimDX, OpenTK itp.), jaki byłby najlepszy pod względem wydajności sposób implementacji renderera WPF (jak w, będzie rysować to, co biblioteka grafu każe mu rysować?

Zasadniczo otrzymana Kontrola WPF działa jak płótno, ale musi być SUPER lekka i nie mieć żadnych schludnych funkcji WPF, poza tym zapewnia mi sposób na rysowanie moich okręgów, linii i innych kształtów :)

EDIT:

W zasadzie chcę wiedzieć: jaka jest droga? Czy Mogę rozszerzyć Canvas jako "Host" dla mojej grafiki, a następnie dodać własną implementację interfejsu użytkownika? Albo mogę mieć jedną klasę, która może narysować wszystko (jak w, jeden mega super ultra graphic). Podobnie jak nadpisywanie OnPaint w GDI lub metoda Paint w Javie (która daje obiekt graficzny do robienia wszystkiego).

Author: Lennard Fonteijn, 2011-09-09

3 answers

Polecam lekturę Optymalizacja wydajności: grafika 2D i obrazowanie (Martwy link -- czytelny przez Internet Archive) -

Zasadniczo, Drawing obiekty będą lżejsze niż Shapes, ogólnie. To jest prawdopodobnie to, czego chcesz użyć.

 11
Author: Reed Copsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-02 22:09:19

Ogólnie rzecz biorąc, lepszą wydajność uzyskuje się dzięki usługom niższego poziomu. W WPF oznacza to rodzinę obiektów Drawing. Wszystko co dostajesz to: Drawing, DrawingGroup, GeometryDrawing, GlyphRunDrawing, ImageDrawing, i VideoDrawing. Są one jednak wystarczające dla wszystkich potrzeb. Używanie tych typów jest bardzo przyjazne dla WPF, ponieważ Drawing jest jednostką koncepcyjną, którą WPF wymienia z akceleratorem GPU, prawdopodobnie zachowując go i zarządzając nim tam, jeśli to możliwe. Działa to, ponieważ Drawing wyraża się w kategoriach przenośnego rysunku wektorowego prymitywy.

Gdy jednak zaczniesz przebudowywać swoją aplikację wokół Drawings, możesz potrzebować trochę interakcji z kodem wyższego poziomu, który nadal opiera się na UIElement, FrameworkElement, itd. Jedną z rzeczy, której nie znalazłem wbudowanego w WPF, jest prosty sposób na owinięcie rysunku jako frameworka w możliwie najniższy możliwy sposób. DrawingVisual nie jest kompletnym rozwiązaniem, ponieważ wywodzi się tylko z Visual - co oznacza, że nadal wymaga elementu hostingowego.

Następująca klasa będzie hostuje dowolny WPF Drawing bezpośrednio bez użycia pośredniego DrawingVisual. Dodałem wsparcie dla FrameworkElement'S Margin właściwości (bez kary wydajności, jeśli nieużywane), ale niewiele więcej. Dzięki pojedynczemu wątkowi renderowania WPF można bezpiecznie i łatwo buforować pojedynczy obiekt TranslateTransform w celu implementacji marginesu. Polecam dostarczyć tylko rysunki, które zostały zamrożone; w rzeczywistości w wersji, której używam, mam do tego prawo w konstruktorze.

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();
    }
};
[[23]} [edit:] to też przydatne przy wstawianiu WPF Drawing do właściwości InlineUIContainer.Child (tzn. przy użyciu TextBlock.InlinesCollection do bardziej bogatego formatowania zawartości bloku tekstowego).
 5
Author: Glenn Slayden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-01 20:31:47

Losowanie wydaje się być słusznym wyborem:

DrawingVisual to lekka Klasa rysunku, która służy do renderowanie kształtów, obrazów lub tekstu. Ta klasa jest uważana za lekką ponieważ nie zapewnia układu ani obsługi zdarzeń, co poprawia jego wydajność. Z tego powodu rysunki są idealne dla tła i Clipart.

Source: Using DrawingVisual Objects

Więc to wydaje się być absolutnie to, o co prosisz, Płótno SUPER lekki.

 0
Author: Davide Piras,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-09 19:44:54