我有一个问题,因为一周后我无法修复,我希望有人可能曾经历过这个。
我正在使用带有Windows窗体项目的SharpDX,基本上有一个带有图片框的表单和一些面板。
当我缩放或翻译图像时,典型的Swapchain.Present(1,PresentFlags.None)效果很好。然而,我遇到这种奇怪的情况,当我最小化我的屏幕并重新打开它时,所有交换链内容都被隐藏,就像它已被删除一样。但是,我知道它没有,这可能是GDI刷新和SharpDX之间的竞争条件。
所以,我试图在每个控件中覆盖WndProc(Message m)并处理它的paint和eraseBackground事件。这不起作用。当我调试时,Windows消息总是不同的,所以很难弄清楚可能出错的地方。
如果有人在Windows窗体上混合SharpDX(或directX)时遇到过这种行为,我真的很想回答。
以下是我处理SharpDX DeviceContext的resize事件的方法
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不需要此功能,因为它是控件上的绘制层。
答案 0 :(得分:1)
当您只想调整交换链的大小时,您不必重新创建DeviceContext。也许这是问题的第一个原因,因为交换链是使用与后备缓冲区不同的DeviceContext创建的。 对我来说,这是在C#中工作的:
首先将eventhandlers添加到控件的resize事件中。无需覆盖WM_PAINT:
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;
用这个我可以保存控件的旧尺寸进行比较。我只是在调整大小完成后调整交换链的大小而不是每个事件(例如调整窗口大小时)。如果控件未最小化,我也只会调整大小:
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(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);
}
}