C# Windows窗体上的SharpDX-最小化屏幕时的竞争条件

C# Windows窗体上的SharpDX-最小化屏幕时的竞争条件,c#,winforms,directx,sharpdx,C#,Winforms,Directx,Sharpdx,我有一个问题,一个星期以来我一直无法解决,我希望有人曾经经历过 我在windows窗体项目中使用SharpDX,基本上有一个带有图片盒和一些面板的窗体 当我缩放或转换图像时,典型的Swapchain.Present(1,PresentFlags.None)效果很好。然而,我遇到了这样一种奇怪的情况:当我最小化屏幕并重新打开它时,所有的swapchain内容都被隐藏了,就像它被擦除了一样。然而,我知道它没有,这可能是GDI刷新和SharpDX之间的竞争条件 所以,我试图覆盖每个控件中的WndPro

我有一个问题,一个星期以来我一直无法解决,我希望有人曾经经历过

我在windows窗体项目中使用SharpDX,基本上有一个带有图片盒和一些面板的窗体

当我缩放或转换图像时,典型的Swapchain.Present(1,PresentFlags.None)效果很好。然而,我遇到了这样一种奇怪的情况:当我最小化屏幕并重新打开它时,所有的swapchain内容都被隐藏了,就像它被擦除了一样。然而,我知道它没有,这可能是GDI刷新和SharpDX之间的竞争条件

所以,我试图覆盖每个控件中的WndProc(消息m),并处理它的绘制和擦除背景事件。这是行不通的。当我调试时,windows消息总是时不时地不同,所以很难找出可能的错误

如果有人在Windows窗体上混合SharpDX(或directX)时遇到过这种情况,我真的很想知道答案

下面是我如何处理SharpDX DeviceContext的调整大小事件

Public Overrides Sub Resize(Width As Integer, Height As Integer)
      If m_SwapChain IsNot Nothing Then
         If m_BackBuffer IsNot Nothing Then
            m_BackBuffer.Dispose()
         End If
         If m_2DDeviceContext IsNot Nothing Then
            m_2DDeviceContext.Dispose()
         End If
         If m_2DTarget IsNot Nothing Then
            m_2DTarget.Dispose()
         End If

         m_SwapChain.ResizeBuffers(2, Width, Height, Format.B8G8R8A8_UNorm, SwapChainFlags.GdiCompatible)

         m_BackBuffer = m_SwapChain.GetBackBuffer(Of Surface)(0)

         m_2DDeviceContext = New SharpDX.Direct2D1.DeviceContext(m_2DDevice, SharpDX.Direct2D1.DeviceContextOptions.EnableMultithreadedOptimizations)

         m_2DTarget = New SharpDX.Direct2D1.Bitmap(m_2DDeviceContext, m_BackBuffer, m_Properties)
         m_2DDeviceContext.AntialiasMode = AntialiasMode.PerPrimitive

         m_2DDeviceContext.Target = m_2DTarget

         CType(m_Context, GPUDrawingContext).DeviceContext = m_2DDeviceContext
      End If

   End Sub
编辑: 在尝试了很多东西之后,我意识到当我调用base.Wndproc(m)其中m=WM_PAINT时,它是正确的

我不能忽略paint消息,因为如果忽略,我的控件仍然无效,它将向事件队列添加一个新的WM_paint,并将我发送到一个无限循环中。我真的不能做base.Wndproc(m),因为这是我的交换链隐藏的地方


因为SharpDX不需要此函数,因为它是控件上的一个绘制层,所以它们可以处理(忽略)此事件消息而不将其返回到循环中

当您只想调整交换链的大小时,不必重新创建DeviceContext。可能这是问题的第一个原因,因为swapchain是使用与backbuffer不同的DeviceContext创建的。 对我来说,这是在C#工作:

首先将EventHandler添加到控件的resize事件中。无需覆盖WM_油漆:

form.ResizeBegin += (o, e) => {
    formHeight = ((Form)o).Height;
    formWidth = ((Form)o).Width;
};
form.ResizeBegin += (o, e) => {
    isResizing = true;
};
form.ResizeEnd += (o, e) => {
    isResizing = false;
    HandleResize(o, e);
};
form.SizeChanged += HandleResize;
有了它,我可以保存控件的旧大小以供比较。我只是在调整大小完成后调整swapchain的大小,而不是针对每个事件(如调整窗口大小时)。此外,我将仅在控件未最小化时调整大小:

private void HandleResize(object sender, System.EventArgs e) {
    Form f = (Form)sender;
    if ((f.ClientSize.Width != formWidth || f.ClientSize.Height != formHeight)
        && !isResizing
        && !(f.WindowState == FormWindowState.Minimized)) {
        formWidth = f.ClientSize.Width;
        formHeight = f.ClientSize.Height;

        DoResize(formWidth, formHeight);
    }
}
最后,DoResize如下所示(renderTarget是我的自定义类):

private void DoResize(整数宽度、整数高度){
renderTarget.Dispose();
swapChain.ResizeBuffers(1,宽度,高度,格式.R8G8B8A8_UNorm,SwapChainFlags.AllowModeSwitch);
使用(var resource=resource.FromSwapChain(swapChain,0)){
//使用新的backbuffer重新创建渲染目标
renderTarget.Resize(宽度、高度、资源);
}
}

您能否展示一些代码(特别是如何处理调整大小事件)?否则,很难猜测到底发生了什么。我编辑了我的帖子,添加了如何处理SharpDX中deviceContext的大小调整,但我不确定这是否是您想要看到的。(我不认为这是因为它)我确实记得最小化是将大小设置为0的情况(尝试创建任何大小为零的swapchain当然会带来各种问题)。我将首先检查这种情况(在这种情况下不重建swapchain)。此外,您应该最终确保在最小化表单时不执行任何操作(例如不执行任何绘图/演示调用)。这在主循环开始时很容易做到(通过检查表单标志)。除了所有windows事件消息之外,在最小化上没有任何操作。另外,我的类用于两个项目(都是windows窗体),我只在一个项目中遇到这个问题,而在另一个项目中没有。所以我最好的选择可能是因为这个项目有孩子,而另一个没有?pictureBox的孩子可以刷新pictureBox,删除我的内容吗?
private void DoResize(int width, int height) {
    renderTarget.Dispose();
    swapChain.ResizeBuffers(1, width, height, Format.R8G8B8A8_UNorm, SwapChainFlags.AllowModeSwitch);
    using (var resource = Resource.FromSwapChain<Texture2D>(swapChain, 0)) {
        //recreate the rendertarget with the new backbuffer
        renderTarget.Resize(width, height, resource);
    }
}