在WPF中有效地绘制二维网格

时间:2012-10-20 23:18:04

标签: c# wpf winforms

这是一个Windows窗体程序,它绘制一个随机着色为黑色或红色的二维方格网格:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Forms_Panel_Random_Squares
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            Width = 350;
            Height = 350;

            var panel = new Panel() { Dock = DockStyle.Fill };

            Controls.Add(panel);

            var random = new Random();

            panel.Paint += (sender, e) =>
                {
                    e.Graphics.Clear(Color.Black);

                    for (int i = 0; i < 30; i++)
                        for (int j = 0; j < 30; j++)
                        {
                            if (random.Next(2) == 1)
                                e.Graphics.FillRectangle(
                                    new SolidBrush(Color.Red),
                                    i * 10,
                                    j * 10,
                                    10,
                                    10);
                        }
                };
        }
    }
}

结果程序看起来像这样:

enter image description here

这是对每个方块使用Rectangle个对象的WPF(天真)翻译:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace WPF_Canvas_Random_Squares
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Width = 350;
            Height = 350;

            var canvas = new Canvas();

            Content = canvas;

            Random random = new Random();

            Rectangle[,] rectangles = new Rectangle[30, 30];

            for (int i = 0; i < rectangles.GetLength(0); i++)
                for (int j = 0; j < rectangles.GetLength(1); j++)
                {
                    rectangles[i, j] =
                        new Rectangle()
                        {
                            Width = 10,
                            Height = 10,
                            Fill = random.Next(2) == 0 ? Brushes.Black : Brushes.Red,
                            RenderTransform = new TranslateTransform(i * 10, j * 10)
                        };

                    canvas.Children.Add(rectangles[i, j]);
                }
        }
    }
}

由于世界上每个单元都有Rectangle对象的开销,因此WPF版本的内存效率似乎更低。

有没有办法以与Forms版本一样高效的样式编写此程序?或者没有办法创建所有这些Rectangle个对象?

2 个答案:

答案 0 :(得分:2)

这是一个纯WPF解决方案。 FrameworkElement是子类。这个新的子类(DrawingVisualElement)公开了一个DrawingVisual对象,可用于绘制。

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

namespace DrawingVisualSample
{
    public class DrawingVisualElement : FrameworkElement
    {
        private VisualCollection _children;

        public DrawingVisual drawingVisual;

        public DrawingVisualElement()
        {
            _children = new VisualCollection(this);

            drawingVisual = new DrawingVisual();
            _children.Add(drawingVisual);
        }

        protected override int VisualChildrenCount
        { 
            get { return _children.Count; } 
        }

        protected override Visual GetVisualChild(int index)
        {
            if (index < 0 || index >= _children.Count)
                throw new ArgumentOutOfRangeException();

            return _children[index];
        }
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Width = 350;
            Height = 350;

            var stackPanel = new StackPanel();

            Content = stackPanel;

            var drawingVisualElement = new DrawingVisualElement();

            stackPanel.Children.Add(drawingVisualElement);

            var drawingContext = drawingVisualElement.drawingVisual.RenderOpen();

            var random = new Random();

            for (int i = 0; i < 30; i++)
                for (int j = 0; j < 30; j++)    
                    drawingContext.DrawRectangle(
                        random.Next(2) == 0 ? Brushes.Black : Brushes.Red,
                        (Pen)null,
                        new Rect(i * 10, j * 10, 10, 10));

            drawingContext.Close();
        }
    }    
}

答案 1 :(得分:0)

可以混合使用WPF和Forms。因此,可以通过WindowsFormsHost将Panel嵌入到WPF窗口中,而不是使用纯Forms路径。这是一个WPF程序,用于演示:

using System;
using System.Windows;
using System.Windows.Forms.Integration;
using System.Drawing;

namespace WindowsFormsHost_Random_Squares
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Width = 350;
            Height = 350;

            Random random = new Random();

            var windowsFormsHost = new WindowsFormsHost();

            Content = windowsFormsHost;

            var panel = new System.Windows.Forms.Panel()
            { Dock = System.Windows.Forms.DockStyle.Fill };

            windowsFormsHost.Child = panel;

            panel.Paint += (sender, e) =>
                {
                    e.Graphics.Clear(System.Drawing.Color.Black);

                    for (int i = 0; i < 30; i++)
                        for (int j = 0; j < 30; j++)
                        {
                            if (random.Next(2) == 1)
                                e.Graphics.FillRectangle(
                                    new SolidBrush(System.Drawing.Color.Red),
                                    i * 10,
                                    j * 10,
                                    10,
                                    10);
                        }
                };
        }
    }
}