如何在 WPF 中的窗口上绘图(最佳实践)?
我正在尝试编写一个类似小型交互式游戏的应用程序,其中我需要一个在屏幕上绘制的 Draw
方法,但无法弄清楚如何构建 WPF 的方法。
如果这是 Winforms
,我可以使用:
public void Draw (Graphics g)
{
}
但是对于 WPF 窗口
,我应该在 xaml 中添加什么(目前只有一个 Grid
>),这个 Draw
方法应该接收什么作为参数?
首先我想这样做以使其正常工作,然后我可以考虑如何使其更加 WPF
等。但现在我更感兴趣的是让它正常工作。
I am trying to write a small interactive game-like application, where I need to have a Draw
method that's gonna draw on screen, but can't figure out how to structure the method for WPF.
If this was Winforms
, I could use:
public void Draw (Graphics g)
{
}
But for a WPF Window
, what should I have on it in the xaml (currently only have a Grid
), and what should this Draw
method receive as an argument?
First I want to do it like this to get it working, then I can think about how to make it more WPF
, etc. But now I am more interested in getting this to work.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
通常,您在 WPF 中以完全不同的方式“绘制”。
在Windows Forms/GDI中,图形API是立即模式图形API。每次窗口刷新/失效时,您都可以使用 Graphics 显式绘制内容。
然而,在 WPF 中,事情的工作方式有所不同。您很少直接绘制 - 相反,它是保留模式图形 API。您告诉 WPF 您想要对象的位置,它会为您处理绘图。
最好的思考方式是,在 Windows 窗体中,您会说“从 X1 到 Y1 画一条线。然后从 X2 到 Y2 画一条线。然后...”。由于屏幕无效,每次需要“重画”时都需要重复此操作。
相反,在 WPF 中,您可以说“我想要一条从 X1 到 Y1 的线。我想要一条从 X2 到 Y2 的线。”然后,WPF 决定何时以及如何为您绘制它。
这是通过将形状放置在画布上,然后让 WPF 完成所有艰苦的工作来完成的。
Typically, you "draw" in WPF in a completely different manner.
In Windows Forms/GDI, the graphics API is an immediate mode graphics API. Each time the window is refreshed/invalidated, you explicitly draw the contents using Graphics.
In WPF, however, things work differently. You rarely ever directly draw - instead, it's a retained mode graphics API. You tell WPF where you want the objects, and it takes care of the drawing for you.
The best way to think of it is, in Windows Forms, you'd say "Draw a line from X1 to Y1. Then draw a line from X2 to Y2. Then ...". And you repeat this every time you need to "redraw" since the screen is invalidated.
In WPF, instead, you say "I want a line from X1 to Y1. I want a line from X2 to Y2." WPF then decides when and how to draw it for you.
This is done by placing the shapes on a Canvas, and then letting WPF do all of the hard work.
当需要快速绘制的对象太多(巨大的可视化树)时,另一种选择是使用
WriteableBitmap
。只需使用Pixels
属性设置像素和/或使用Render
方法绘制UIElements
。When there are just too many objects to be drawn very quickly (huge Visual Tree) another option would be to use a
WriteableBitmap
. Just use thePixels
property to set the pixels and/or use theRender
method to drawUIElements
.我更喜欢使用 OnRender 方法,如下例所示:
I preffer to use OnRender method like in this example:
要在 WPF 中实现 Draw 循环类型行为,您可以使用 CompositionTarget.Rendering 事件。当 WPF 绘图系统绘制帧时,每帧都会引发一次。
正如其他人指出的那样,这对 WPF 不太友好,但它可以工作,并且可用于从 WPF 应用程序中获得更直接的绘图行为。
在大多数情况下,您将使用单个根画布并更新 CompositionTarget.Rendering 事件上元素的画布位置。
例如,要使椭圆飞过屏幕,请执行以下操作:
在您的 XAML 中(对于大小为 640 x 480 的窗口):
在上述 XAML 所在窗口的代码隐藏中(确保添加引用到 System.Windows.Media 以便查看 CompsitionTarget 对象:
To Implement a Draw loop type behavior in WPF you can use the CompositionTarget.Rendering event. This is raised once per frame when the WPF drawing system is painting frames.
As others have pointed out this is not very WPF friendly but it will work and can be used to get more immediate drawing behavior out of a WPF app.
In most cases you would use a single root canvas and update say the Canvas position of an element on the CompositionTarget.Rendering event.
For example to make a ellipse fly all over the screen do this:
In your XAML (For a Window that is 640 by 480 in size):
In your Code behind for the Window that the above XAML is in (Make sure to add a reference to System.Windows.Media in order to see the CompsitionTarget object :
您应该添加一个画布(或更改画布的网格),然后在其上绘图。 这是 Microsoft 关于在画布上绘图的内容
另外,我不不知道这个其他问题与您的问题有什么关系,但您可能想检查一下出去。
Yow should add a Canvas (or change the Grid for a Canvas) and then draw over it. Here is Microsoft tut on drawing over a canvas
Also, I don't know how related is this other question to yours, but you might want to check it out.