C# 在WPF中高效地绘制二维网格

C# 在WPF中高效地绘制二维网格,c#,wpf,winforms,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() { InitializeC

这是一个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);
                        }
                };
        }
    }
}
由于世界上的每个单元都有一个
矩形
对象的开销,WPF版本的内存效率似乎要低得多


有没有一种方法可以像表单版本那样高效地编写这个程序?或者没有办法创建所有这些
矩形
对象吗?

可以混合使用WPF和表单。因此,可以通过
WindowsFormsHost
将面板嵌入到WPF窗口中,而不是执行纯表单路线。下面是一个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);
                        }
                };
        }
    }
}
使用系统;
使用System.Windows;
使用System.Windows.Forms.Integration;
使用系统图;
命名空间WindowsFormsHost\u随机方
{
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
宽度=350;
高度=350;
随机=新随机();
var windowsFormsHost=新windowsFormsHost();
Content=windowsFormsHost;
var panel=new System.Windows.Forms.panel()
{Dock=System.Windows.Forms.DockStyle.Fill};
windowsFormsHost.Child=面板;
panel.Paint+=(发送器,e)=>
{
e、 图形。清晰(系统。绘图。颜色。黑色);
对于(int i=0;i<30;i++)
对于(int j=0;j<30;j++)
{
if(随机下一个(2)==1)
e、 图形填充矩形(
新的SolidBrush(系统、图纸、颜色、红色),
i*10,
j*10,
10,
10);
}
};
}
}
}

这里有一个纯WPF解决方案<代码>框架元素是子类。这个新的子类(
DrawingVisualElement
)公开了一个可用于绘制的
DrawingVisualElement
对象

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();
        }
    }    
}
使用系统;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Media;
命名空间DrawingVisualSample
{
公共类DrawingVisualElement:FrameworkElement
{
儿童私人视觉采集;
公共绘图视觉绘图视觉绘图;
公共绘图VisualElement()
{
_儿童=新的视觉集合(本);
drawingVisual=新drawingVisual();
_添加(drawingVisual);
}
受保护的重写int VisualChildrenCount
{ 
获取{return\u children.Count;}
}
受保护的重写Visual GetVisualChild(int索引)
{
如果(索引<0 | |索引>=_children.Count)
抛出新ArgumentOutOfRangeException();
返回子项[索引];
}
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
宽度=350;
高度=350;
var stackPanel=新的stackPanel();
内容=stackPanel;
var drawingVisualElement=新的drawingVisualElement();
stackPanel.Children.Add(drawingVisualElement);
var drawingContext=drawingVisualElement.drawingVisual.RenderRopen();
var random=新的random();
对于(int i=0;i<30;i++)
对于(int j=0;j<30;j++)
drawingContext.DrawRectangle(
随机。下一(2)=0?画笔。黑色:画笔。红色,
(笔)空,
新的Rect(i*10,j*10,10,10));
drawingContext.Close();
}
}    
}

您是想要对象还是仅仅改变背景颜色,是否需要使用画布而不是网格?我想在二维数组中渲染状态。因此,我不需要视图级别的重对象表示suggests@MarkHall谢谢你给我这个答案的指针!我添加了一个演示如何使用
DrawingVisual
DrawingContext
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();
        }
    }    
}