Direct2D / GDI +和慢速Windows表格绘图 – 可以做什么?

我正在使用Visual Studio 2008,.NET C#2.0-3.5和Windows Forms进行大量工作,我注意到,就像我之前的许多人一样,GDI +在绘制控件时非常慢。 请注意 ,我不会非常处理图像(JPG,GIF等)。 图像仅在某些地方作为图标。 这实际上是控件/表格/等,绘制速度很慢。

问题在于您可以看到正在绘制的控件,并且可能需要几秒钟才能绘制一组看似简单的控件。 即,它的滞后和可怕。

我已经进行了测试,我只是在表格上放了一些标签(40-50),按F5运行并且必须等待它们被绘制。 再次,滞后,而不是一个非常好的经验。

那么,WPF可能会解决这个问题,但我/我们还没有准备好转向WPF。 所以我正在寻找解决方法或修复方法,我偶然发现了Direct2D,并在阅读其他一些库时。

让我有点困惑,因此这些问题:

1)首先,我想要的是一个相当简洁的方法,用更快的速度和硬件加速方法替换 GDI +。 是否可以在不转到WPF且无需重写所有Windows窗体代码的情况下执行此操作?

每当我在Direct2D上阅读任何内容时,我都会看到通常可怕的C ++代码的长块,告诉我如何手动编写代码来绘制。 我不要那个。

2)在网上阅读时,我偶然发现了SlimDX,但我无法弄清楚如何使用它(我承认,我写作时并没有尝试过)。 可以说我已经有了一个GUI应用程序(Windows窗体,标准C#代码) – 我可以以某种方式使用SlimDX(或类似的东西)来“替换”GDI +而不需要太多的重写吗?

我的问题是我找不到任何示例或告诉我是否可以在我已经创建的Windows窗体软件中使用SlimDX,Direct2D或其他类似的东西,如果可能的话 – 如何做到这一点。

希望我不要太模糊=)

==编辑== 2010-09-22

我在我的真实应用程序中进行了一些测试,并将其中一个缓慢的事情分离出来:

当我向UserControl中的某些标签添加文本时,控件会自行resize以适合文本。 例如,包含GroupControl的位会适应刚刚添加到标签的.Text属性的文本的大小。

大约有10个Label控件。 第一次更新标签,从而更改尺寸时,整个过程大约需要500毫秒。 标签第二次更新, 没有大小更改,大约需要0毫秒。

==编辑2 == 2010-09-22

发现其中一个减速。 然后将一个String添加到Text-property,如果正在添加的文本的字符串长度与更新之前的文本不同,则它很慢。

我使用DevExpress库,LabelControls可以设置为AutoSizeMode。 如果我将其设置为“无”,则在添加长度与前一文本不同的文本时,滞后将消失。 我猜这个问题对于普通的Label-control是相同的,因为它也有一个AutoSize = true / false设置。

然而,它是一个“解决方法”,但仍然certificate了我的观点 – 当resize非常蹩脚时它真的很慢。

上面的许多海报都有很好的观点。 我自己在GDI +中创建了一个3D CAD应用程序,如果它正确实现,它发现它足够快。 然而,使用控件会立刻让我觉得这是一种非常尴尬的做事方式。 控件是一个相当大的对象,在这种情况下,有很多理由可以创建自己的控件。

我建议你研究一下保留模式绘图系统 。 它很容易实现,并且在大多数情况下会覆盖您的情况。 你必须自己创建绘图逻辑,但这很有趣,会给你更多的灵活性:)

在你的第一个问题上,我不得不使用GDI做一些图像处理的东西,这些东西在GDI +下花了很多年。 这是4 – 5年前,使用托管C#与GDI合作是一种痛苦 – 不确定它现在已经改变了多少。 有很多好的和快速的function,比如BitBlt,绘图速度非常快,但你需要非常小心地释放资源(句柄)和内存。 我还有另一个问题,那就是将结果保存为JPEG,而且它在GDI中不存在,所以我不得不使用CxImage读取HBitmap然后保存它。

总而言之,GDI非常快速而强大。 如果在DirectX中有更好的抽象,可能你最好使用它们。

我正在看一些相同的问题。 我正在编写一个应用程序,需要能够非常有效地渲染2d图形,因为一些用户可以同时打开10-50个窗口。 有一点要考虑的是,没有人在这里谈论的事实是direct2d只能用于带有Service Pack 2及更高版本Vista的计算机。 另外,根据这个链接:

http://www.tomshardware.com/news/msft-windows-xp-windows-7-market-share-win7,13876.html

截至2011年11月,38.5%的Windows用户仍在使用XP。因此,如果将应用程序销售给仍在运行XP的大量用户是一个问题(或者您的市场基础是主要使用XP的第三世界国家),然后你应该去:

  1. Direct2d用于较新的操作系统,GDI +用于XP系统。

  2. XNA – 与XP兼容,也可以与更新的操作系统一起使用。 请参阅此链接: http : //msdn.microsoft.com/en-us/library/bb203925.aspx

  3. SlimDX – 在第一个答案中提到。 支持XP以及更新的操作系统。 请参阅: http : //slimdx.org/和http://slimdx.org/features.php

  4. 如果您关心Windows,Linux,Max等之间的兼容性,请使用OpenTK。

您还应该知道GDI +存在一个错误,导致它在最初发布时性能非常差。 请参阅以下链接,为什么一些开发人员声称微软打破了使用GDI +的应用程序的Windows 7 gui:

http://www.windows7taskforce.com/view/3607

或使用此字符串从您最喜欢的搜索引擎进行网络搜索:“Windows 7上的”gdi + bug slow“。

您可以尝试托管directx,但他们不再支持它(转移到XNA)。 老实说,除非你有一台糟糕的电脑或大量的控制器,否则我不知道为什么它会如此糟糕。 如果你在主线程上做了一些cpu密集的东西,把它移到一个单独的线程。 这是我能想到的另一个原因导致这种滞后。

我们在C#应用程序中使用SlimDX ….但我们实际上在做3D。 我们编写了自己的2D库,可以进行简单的2D绘图。 SlimDX只是DirectX的轻量级包装器。 因此,您将获得DirectX的所有专业和缺点。 就像那样,如果它不存在则模仿显卡是你的问题。

如果你想要绘制到屏幕外位图的东西,我会选择WPF,因为它与C#很好地集成,大多数在各处工作,并且在有硬件可用时加速。 您可以将输出复制到位图并在常规GDI / Winforms中使用它。 但它只会比GDI +更快,如果你做相当复杂的东西(大量的filter,混合纹理等……)。

编辑:

在回应评论时,我构建了一个小样本表格。 第一次切换时需要等待几秒钟,但之后会有响应。 比我预期的要慢,但无论如何都可以使用。 如果这是关于他在他的应用程序中看到的表现,请Ted评论。

public class Form1 : Form { public Form1() { InitializeComponent(); // *** EDIT *** this.tabPage1.SuspendLayout(); this.tabPage2.SuspendLayout(); this.tabControl1.SuspendLayout(); this.SuspendLayout(); FillTab(tabPage1, Color.White); FillTab(tabPage2, Color.Yellow); // *** EDIT *** this.tabPage1.ResumeLayout(false); this.tabPage2.ResumeLayout(false); this.tabControl1.ResumeLayout(false); this.ResumeLayout(false); } private static void FillTab(TabPage tabPage, Color color) { for (int i = 0; i < 200; ++ i) { int left = (i % 5) * 320; int topOffset = (i / 5) * 23; tabPage.Controls.Add(new Label { Left = left, Top = topOffset, Width = 100, Text = "Label" }); tabPage.Controls.Add(new TextBox() { BackColor = color, Left = left + 100, Top = topOffset, Width = 100, Text = tabPage.Text }); tabPage.Controls.Add(new ComboBox { BackColor = color, Left = left + 200, Top = topOffset, Width = 100 }); } } ///  /// Required designer variable. ///  private System.ComponentModel.IContainer components = null; ///  /// Clean up any resources being used. ///  /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code ///  /// Required method for Designer support - do not modify /// the contents of this method with the code editor. ///  private void InitializeComponent() { this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); this.tabPage2 = new System.Windows.Forms.TabPage(); this.tabControl1.SuspendLayout(); this.SuspendLayout(); // // tabControl1 // this.tabControl1.Controls.Add(this.tabPage1); this.tabControl1.Controls.Add(this.tabPage2); this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; this.tabControl1.Location = new System.Drawing.Point(0, 0); this.tabControl1.Name = "tabControl1"; this.tabControl1.SelectedIndex = 0; this.tabControl1.Size = new System.Drawing.Size(292, 266); this.tabControl1.TabIndex = 0; // // tabPage1 // this.tabPage1.Location = new System.Drawing.Point(4, 22); this.tabPage1.Name = "tabPage1"; this.tabPage1.Padding = new System.Windows.Forms.Padding(3); this.tabPage1.Size = new System.Drawing.Size(284, 240); this.tabPage1.TabIndex = 0; this.tabPage1.Text = "tabPage1"; this.tabPage1.UseVisualStyleBackColor = true; // // tabPage2 // this.tabPage2.Location = new System.Drawing.Point(4, 22); this.tabPage2.Name = "tabPage2"; this.tabPage2.Padding = new System.Windows.Forms.Padding(3); this.tabPage2.Size = new System.Drawing.Size(245, 217); this.tabPage2.TabIndex = 1; this.tabPage2.Text = "tabPage2"; this.tabPage2.UseVisualStyleBackColor = true; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(292, 266); this.Controls.Add(this.tabControl1); this.Name = "Form1"; this.Text = "Form1"; this.tabControl1.ResumeLayout(false); this.ResumeLayout(false); } #endregion private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.TabPage tabPage2; }