如何在WPF中绘制窗口(最佳实践)?

Joa*_*nge 24 .net c# wpf graphics xaml

我正在尝试编写一个类似于交互式游戏的小应用程序,我需要有一个Draw方法可以在屏幕上绘制,但无法弄清楚如何构建WPF方法.

如果是这样Winforms,我可以使用:

public void Draw (Graphics g)
{

}
Run Code Online (Sandbox Code Playgroud)

但是对于a WPF Window,我应该在xaml中拥有Grid什么(目前只有a ),这个Draw方法应该作为参数接收什么?

首先,我想这样做是为了让它工作,然后我可以考虑如何使它更多WPF,等等.但现在我更感兴趣的是让它工作.

Ree*_*sey 20

通常,您以完全不同的方式在WPF中"绘制".

在Windows Forms/GDI中,图形API是立即模式图形API.每次刷新/无效窗口时,都使用Graphics显式绘制内容.

但是,在WPF中,事情的工作方式不同.你很少直接绘制 - 相反,它是一个保留模式图形API.你告诉WPF你想要对象的位置,它会为你处理绘图.

想到它的最好方法是,在Windows窗体中,你会说"从X1到Y1绘制一条线.然后从X2到Y2绘制一条线.然后......".每次需要"重绘"时重复此操作,因为屏幕无效.

相反,在WPF中,你说"我想要一条从X1到Y1的线.我想要一条从X2到Y2的线." WPF然后决定何时以及如何为您绘制它.

这是通过将形状放在Canvas上,然后让WPF完成所有艰苦的工作来完成的.

  • @Joan:您不能-就像WinForms一样-所有UI内容都必须在UI线程上发生,因此您需要使用Dispatcher.Invoke将其编组回UI线程。 (3认同)

Ern*_*rno 9

当有太多的对象要快速绘制时(巨大的Visual Tree),另一种选择是使用a WriteableBitmap.只需使用该Pixels属性设置像素和/或使用Render方法绘制UIElements.


Mar*_*acz 6

我喜欢在这个例子中使用OnRender方法:

protected override void OnRender(DrawingContext drawingContext)
{
    base.OnRender(drawingContext);
     drawingContext.DrawRectangle(null, new Pen(Brushes.Black, 2), new Rect(0, 0, ActualWidth, Height));
}
Run Code Online (Sandbox Code Playgroud)

  • 这将有效,但在WPF中很少是个好主意.使用Canvas通常是一种更好的做法. (4认同)
  • 这不是性能问题,画布更重吗? (2认同)

Bra*_*ham 6

要在 WPF 中实现 Draw 循环类型行为,您可以使用CompositionTarget.Rendering事件。当 WPF 绘图系统绘制帧时,每帧都会引发一次。

正如其他人指出的那样,这对 WPF 不太友好,但它可以工作,并且可用于从 WPF 应用程序中获得更直接的绘图行为。

在大多数情况下,您将使用单个根画布并更新 CompositionTarget.Rendering 事件上元素的画布位置。

例如,要使椭圆飞过整个屏幕,请执行以下操作:

在您的 XAML 中(对于大小为 640 x 480 的窗口):

<Canvas x:Name="theCanvas">
    <Ellipse x:Name="theEllipse" Height="10" Width="10" Fill="Black" />     
</Canvas>
Run Code Online (Sandbox Code Playgroud)

在上述 XAML 所在窗口的代码隐藏中(确保添加对 System.Windows.Media 的引用以便查看 CompsitionTarget 对象:

    public static Random rand = new Random();
    public View()
    {
        InitializeComponent();
        CompositionTarget.Rendering += CompositionTarget_Rendering;
    }

    void CompositionTarget_Rendering(object sender, System.EventArgs e)
    {
        double newLeft = rand.Next(0, 640);
        double newTop = rand.Next(0, 480);

        theEllipse.SetValue(Canvas.LeftProperty,newLeft);
        theEllipse.SetValue(Canvas.TopProperty, newTop);
    }
Run Code Online (Sandbox Code Playgroud)