C# 将无效设置为自己的位图

C# 将无效设置为自己的位图,c#,winapi,off-screen,wm-paint,C#,Winapi,Off Screen,Wm Paint,我希望在屏幕外将控件渲染为位图,以便快速访问它 不幸的是Control.DrawToBitmap似乎绘制了调用它的整个控件,包括它的所有子控件。在内部,它向位图发出带有自备DC的WM_打印消息。然后,此临时位图将被闪电显示到用户提供的位图。对于我来说,这是不可接受的,我宁愿根据需要更新此位图,以便在需要位图时将性能影响降至最低 在理想情况下,我希望表单的行为就像它在屏幕上是可见的一样(但它不能)。这意味着,如果某个控件的Text属性发生更改,表单将部分无效。捕获相关的消息/事件将允许我为要绘制的

我希望在屏幕外将控件渲染为位图,以便快速访问它

不幸的是
Control.DrawToBitmap
似乎绘制了调用它的整个控件,包括它的所有子控件。在内部,它向位图发出带有自备DC的WM_打印消息。然后,此临时位图将被闪电显示到用户提供的位图。对于我来说,这是不可接受的,我宁愿根据需要更新此位图,以便在需要位图时将性能影响降至最低

在理想情况下,我希望表单的行为就像它在屏幕上是可见的一样(但它不能)。这意味着,如果某个控件的
Text
属性发生更改,表单将部分无效。捕获相关的消息/事件将允许我为要绘制的表单指定我自己的DC,或者简单地将表单DC BitBlt到我自己的DC

我看了一些方向:

  • OnPaint
    中的
    PaintEventArgs
    参数似乎包含一个成员savedGraphicsState,也许可以使用它来确定哪些内容不需要无效
  • 形状可见但在屏幕区域之外的。不过,控件不会被绘制
  • 在窗口上手动调用RedrawWindow(),情况相同

我认为如果该控件被克隆,那么它将起作用,这样您就可以得到一个不位于窗体上且没有子控件的控件:

Control ctrl = ControlFactory.CloneCtrl(this.button3);
Bitmap bmp = new Bitmap(ctrl.Width, ctrl.Height);
ctrl.DrawToBitmap(bmp, new Rectangle(0, 0, ctrl.Width, ctrl.Height));
bmp.Save(@"C:\Users\Oli\Desktop\test.bmp");
我使用了在中找到的lxwde编写的


ControlFactory并不完美,但它足够简单,可以很容易地改进。

我为您制作了一个示例项目,展示了一些onPaint事件。如果你看不出它是这样解决的,只需更新这个例子

问候!

请在此下载:


我认为有两个问题:

  • 查找控件的无效区域(无windows帮助)
  • 仅呈现无效部分
  • 关于第一个问题,我认为你基本上是靠自己。您应该跟踪哪些控件发生了更改,并有需要更新的簿记

    对于第二个问题,您可以尝试自己发送WM_打印消息,并提供一个仅引用小位图的DC。原始DC API允许您偏移和剪裁HDC的有效绘图区域。 如果您非常幸运,windows将从HDC推断渲染区域,如果没有,则完全脱离位图的大多数渲染命令应该非常便宜,因为没有需要更改的像素


    您应该能够通过打印到1x1位图来验证这一点,并测试它是否更快,和/或验证WM_PAINT中发送的剪辑区域是否减小到位图大小。

    我不完全清楚为什么
    DrawToBitmap
    WM_PRINT
    消息)不适合您使用。你担心表现吗?绘制位图不太可能比绘制到屏幕上慢。我需要一个缓冲机制。DrawToBitmap从头开始绘制整个控件,而在普通窗口上使用的无效系统只会更新实际更改的区域。@Frank,你考虑过使用Bitblt吗?是的,但如果窗口在屏幕上实际上不可见,它就不起作用了。@FrankRazenberg似乎在试图创建一个控件,以便在单独的LCD上显示。据推测,他有一个API,允许他向LCD发送位图,但它不是Windows可以识别的显示器,因此他不能简单地在该屏幕上显示控件。为此,他尝试获取屏幕外控件的图像,并在需要更新时得到通知,以便将位图的更新部分发送到单独的屏幕。可能是带宽受限,因此每次发送整个位图不是一个选项。对吗???如果是这样的话,那才是真正的问题。对不起,我看不出这有什么关系。您说您的解决方案不幸地绘制了子控件。我的解决方案没有。我试过用一个包含按钮的面板。它仅将面板绘制到位图,但没有子控件。当控件在屏幕上不可见时,它也可以工作。我真的不明白你想要实现什么。您会说:“我希望表单的行为就像它在屏幕上是可见的一样(但它不能)”。为什么它不能在屏幕上显示?为什么要渲染屏幕上不可见的窗体?渲染窗体的位图将发送到单独的LCD。我希望控件在正常情况下自动验证自身,例如在更改窗口文本时。我还想知道这是什么时候发生的。控制中有一个
    Invalidated
    事件。您可以为所有控件订阅它。
    Private Sub Button1_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles Button1.Paint
        Dim bm As New Bitmap(Me.Button1.Width, Me.Button1.Height, PixelFormat.Format32bppRgb)
    
        Button1.DrawToBitmap(bm, New Rectangle(0, 15, bm.Width -5, bm.Height+2))
        Using gr As Graphics = Graphics.FromImage(bm)
            gr.DrawString(DateTime.Now.ToLongTimeString, Me.Font, Brushes.Lime, 0, 0)
        End Using
        Me.PictureBox1.BackgroundImageLayout = ImageLayout.Tile
        Me.PictureBox1.BackgroundImage = bm
    
    End Sub
        Public Class myTextBox
            Inherits System.Windows.Forms.TextBox
    
    
            Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
                MyBase.OnPaint(e)
                e.Graphics.Clear(Color.Yellow)
                e.Graphics.DrawString(DateTime.Now.ToLongTimeString, Me.Font, Brushes.Gray, 0, 0)
            End Sub
    
            Public Sub New()
                SetStyle(ControlStyles.UserPaint, True)
            End Sub
        End Class