rendering-with-drawingvisual

WPF DrawingVisual Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "rendering-with-drawingvisual" with this command: npx skills add christian289/dotnet-with-claudecode/christian289-dotnet-with-claudecode-rendering-with-drawingvisual

WPF DrawingVisual Patterns

DrawingVisual is a lightweight visual element faster than Shape, suitable for large-scale rendering.

  1. Visual Hierarchy

Visual (abstract) ├── UIElement │ └── FrameworkElement │ └── Shape (heavyweight, event support) │ ├── DrawingVisual ← Lightweight, no events, direct rendering ├── ContainerVisual ← Groups multiple Visuals └── HostVisual ← Cross-thread Visual

  1. DrawingVisual vs Shape

Aspect DrawingVisual Shape

Overhead Low High

Layout Non-participating Participating

Events Manual implementation Built-in support

Data binding Not available Available

Use case Large elements, performance critical Interactive UI

  1. Basic DrawingVisual Host

3.1 FrameworkElement Host

namespace MyApp.Controls;

using System.Collections.Generic; using System.Windows; using System.Windows.Media;

/// <summary> /// Control that hosts DrawingVisual /// </summary> public sealed class DrawingVisualHost : FrameworkElement { private readonly List<Visual> _visuals = [];

protected override int VisualChildrenCount => _visuals.Count;

protected override Visual GetVisualChild(int index)
{
    return _visuals[index];
}

/// &#x3C;summary>
/// Add Visual
/// &#x3C;/summary>
public void AddVisual(Visual visual)
{
    _visuals.Add(visual);
    AddVisualChild(visual);
    AddLogicalChild(visual);
}

/// &#x3C;summary>
/// Remove Visual
/// &#x3C;/summary>
public void RemoveVisual(Visual visual)
{
    _visuals.Remove(visual);
    RemoveVisualChild(visual);
    RemoveLogicalChild(visual);
}

/// &#x3C;summary>
/// Remove all Visuals
/// &#x3C;/summary>
public void ClearVisuals()
{
    foreach (var visual in _visuals)
    {
        RemoveVisualChild(visual);
        RemoveLogicalChild(visual);
    }
    _visuals.Clear();
}

/// &#x3C;summary>
/// Find Visual at coordinate (Hit Testing)
/// &#x3C;/summary>
public Visual? GetVisualAt(Point point)
{
    var hitResult = VisualTreeHelper.HitTest(this, point);
    return hitResult?.VisualHit;
}

}

3.2 Creating DrawingVisual

namespace MyApp.Graphics;

using System.Windows; using System.Windows.Media;

public static class DrawingVisualFactory { /// <summary> /// Create circular DrawingVisual /// </summary> public static DrawingVisual CreateCircle( Point center, double radius, Brush fill, Pen? stroke = null) { var visual = new DrawingVisual();

    using (var dc = visual.RenderOpen())
    {
        dc.DrawEllipse(fill, stroke, center, radius, radius);
    }

    return visual;
}

/// &#x3C;summary>
/// Create rectangle DrawingVisual
/// &#x3C;/summary>
public static DrawingVisual CreateRectangle(
    Rect rect,
    Brush fill,
    Pen? stroke = null)
{
    var visual = new DrawingVisual();

    using (var dc = visual.RenderOpen())
    {
        dc.DrawRectangle(fill, stroke, rect);
    }

    return visual;
}

/// &#x3C;summary>
/// Create text DrawingVisual
/// &#x3C;/summary>
public static DrawingVisual CreateText(
    string text,
    Point origin,
    Brush foreground,
    double fontSize = 12)
{
    var visual = new DrawingVisual();

    var formattedText = new FormattedText(
        text,
        System.Globalization.CultureInfo.CurrentCulture,
        FlowDirection.LeftToRight,
        new Typeface("Segoe UI"),
        fontSize,
        foreground,
        VisualTreeHelper.GetDpi(visual).PixelsPerDip);

    using (var dc = visual.RenderOpen())
    {
        dc.DrawText(formattedText, origin);
    }

    return visual;
}

/// &#x3C;summary>
/// Create image DrawingVisual
/// &#x3C;/summary>
public static DrawingVisual CreateImage(
    ImageSource image,
    Rect rect)
{
    var visual = new DrawingVisual();

    using (var dc = visual.RenderOpen())
    {
        dc.DrawImage(image, rect);
    }

    return visual;
}

}

  1. ContainerVisual (Grouping)

4.1 Using ContainerVisual

namespace MyApp.Graphics;

using System.Windows; using System.Windows.Media;

public sealed class VisualGroup { public ContainerVisual Container { get; } = new();

/// &#x3C;summary>
/// Add child Visual
/// &#x3C;/summary>
public void Add(Visual visual)
{
    Container.Children.Add(visual);
}

/// &#x3C;summary>
/// Remove child Visual
/// &#x3C;/summary>
public void Remove(Visual visual)
{
    Container.Children.Remove(visual);
}

/// &#x3C;summary>
/// Move entire group
/// &#x3C;/summary>
public void SetOffset(double x, double y)
{
    Container.Offset = new Vector(x, y);
}

/// &#x3C;summary>
/// Transform entire group
/// &#x3C;/summary>
public void SetTransform(Transform transform)
{
    Container.Transform = transform;
}

/// &#x3C;summary>
/// Set opacity for entire group
/// &#x3C;/summary>
public void SetOpacity(double opacity)
{
    Container.Opacity = opacity;
}

}

4.2 Hierarchical Visual Structure

// Hierarchical structure example // // ContainerVisual (root) // ├── ContainerVisual (layer 1 - background) // │ ├── DrawingVisual (grid) // │ └── DrawingVisual (background image) // ├── ContainerVisual (layer 2 - content) // │ ├── DrawingVisual (node 1) // │ ├── DrawingVisual (node 2) // │ └── DrawingVisual (connections) // └── ContainerVisual (layer 3 - overlay) // └── DrawingVisual (selection area)

public sealed class LayeredCanvas : FrameworkElement { private readonly ContainerVisual _rootVisual = new(); private readonly ContainerVisual _backgroundLayer = new(); private readonly ContainerVisual _contentLayer = new(); private readonly ContainerVisual _overlayLayer = new();

public LayeredCanvas()
{
    _rootVisual.Children.Add(_backgroundLayer);
    _rootVisual.Children.Add(_contentLayer);
    _rootVisual.Children.Add(_overlayLayer);

    AddVisualChild(_rootVisual);
}

protected override int VisualChildrenCount => 1;

protected override Visual GetVisualChild(int index) => _rootVisual;

public void AddToBackground(DrawingVisual visual)
{
    _backgroundLayer.Children.Add(visual);
}

public void AddToContent(DrawingVisual visual)
{
    _contentLayer.Children.Add(visual);
}

public void AddToOverlay(DrawingVisual visual)
{
    _overlayLayer.Children.Add(visual);
}

}

  1. Hit Testing

5.1 Basic Hit Testing

namespace MyApp.Controls;

using System.Windows; using System.Windows.Input; using System.Windows.Media;

public sealed class InteractiveDrawingHost : FrameworkElement { private readonly List<DrawingVisual> _visuals = []; private DrawingVisual? _hoveredVisual; private DrawingVisual? _selectedVisual;

public InteractiveDrawingHost()
{
    MouseMove += OnMouseMove;
    MouseLeftButtonDown += OnMouseLeftButtonDown;
}

// ... VisualChildrenCount, GetVisualChild implementation omitted ...

private void OnMouseMove(object sender, MouseEventArgs e)
{
    var position = e.GetPosition(this);
    var hitVisual = HitTestVisual(position);

    if (hitVisual != _hoveredVisual)
    {
        // Hover state changed
        _hoveredVisual = hitVisual;
        Cursor = hitVisual is not null ? Cursors.Hand : Cursors.Arrow;
    }
}

private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var position = e.GetPosition(this);
    _selectedVisual = HitTestVisual(position);

    if (_selectedVisual is not null)
    {
        // Handle selected Visual
        OnVisualSelected(_selectedVisual);
    }
}

private DrawingVisual? HitTestVisual(Point point)
{
    DrawingVisual? result = null;

    VisualTreeHelper.HitTest(
        this,
        null,
        hitResult =>
        {
            if (hitResult.VisualHit is DrawingVisual visual)
            {
                result = visual;
                return HitTestResultBehavior.Stop;
            }
            return HitTestResultBehavior.Continue;
        },
        new PointHitTestParameters(point));

    return result;
}

private void OnVisualSelected(DrawingVisual visual)
{
    // Raise selection event
}

}

5.2 Geometry-based Hit Testing

/// <summary> /// Find all Visuals within specific area /// </summary> public List<DrawingVisual> HitTestArea(Rect area) { var results = new List<DrawingVisual>(); var geometry = new RectangleGeometry(area);

VisualTreeHelper.HitTest(
    this,
    null,
    hitResult =>
    {
        if (hitResult.VisualHit is DrawingVisual visual)
        {
            results.Add(visual);
        }
        return HitTestResultBehavior.Continue;
    },
    new GeometryHitTestParameters(geometry));

return results;

}

  1. Advanced Rendering

For advanced patterns, see references/advanced-rendering.md:

  • Large-scale Rendering (Scatter Plot): 10,000+ point rendering example

  • RenderTargetBitmap: Off-screen rendering and PNG export

  • Performance Optimization Tips: Freeze, StreamGeometry, DrawingGroup

  1. References
  • DrawingVisual Class - Microsoft Docs

  • Using DrawingVisual Objects - Microsoft Docs

  • Hit Testing in the Visual Layer - Microsoft Docs

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

converting-html-css-to-wpf-xaml

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

publishing-wpf-apps

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

using-xaml-property-element-syntax

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

managing-styles-resourcedictionary

No summary provided by upstream source.

Repository SourceNeeds Review