C# 将Direct2D渲染重定向到WPF控件
我正在通过C# 将Direct2D渲染重定向到WPF控件,c#,c++,wpf,directx,direct2d,C#,C++,Wpf,Directx,Direct2d,我正在通过Direct2D在visualc++中开发一个绘图应用程序。 我有一个演示应用程序,其中: // create the ID2D1Factory D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pDirect2dFactory); // create the main window HWND m_hwnd = CreateWindow(...); // set the render target of type
Direct2D
在visualc++
中开发一个绘图应用程序。
我有一个演示应用程序,其中:
// create the ID2D1Factory
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pDirect2dFactory);
// create the main window
HWND m_hwnd = CreateWindow(...);
// set the render target of type ID2D1HwndRenderTarget
m_pDirect2dFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(m_hwnd, size),
&m_pRenderTarget
);
当我收到WM_PAINT
消息时,我会画出我的形状
现在,我需要开发一个WPF控件(一种)来表示我的新渲染目标(因此它将替换主窗口m#hwnd
),这样我就可以创建一个新的(C#)WPF项目,主窗口的子窗口是我的自定义面板,而渲染部分保留在本机C++/CLI DLL项目中
我该怎么做?我必须设置什么作为我的新渲染目标
我想使用WPF窗口的句柄:
IntPtr windowHandle = new WindowInteropHelper(MyMainWindow).Handle;
但我需要在我的面板上画画,而不是在我的窗户上
请注意,我不想对渲染部分使用任何WPF类(
Shapes
,DrawingVisuals
…)可能使用WINFORMS,但不使用WPF。
以下是关于WPF如何使用HWNDs的文档:
WPF如何使用Hwnds
为了充分利用WPF的“HWND互操作”,您需要了解WPF是如何实现的
使用HWNDs。对于任何HWND,都不能将WPF渲染与DirectX混合使用
渲染或GDI/GDI+渲染。这有许多含义。
首先,为了完全混合这些渲染模型,必须
创建互操作解决方案,并使用指定的
选择使用的每个渲染模型的互操作。也,
渲染行为会为所渲染的内容创建“空域”限制
互操作解决方案可以实现。“空域”概念是
在主题“技术区域概述”中有更详细的说明。
屏幕上的所有WPF元素最终都由HWND支持。什么时候
创建WPF窗口,WPF创建顶级HWND,并使用
HwndSource将窗口及其WPF内容放入HWND中。这个
应用程序中的其余WPF内容共享该单一HWND。
菜单、组合框下拉列表和其他弹出窗口除外。这些
元素创建自己的顶级窗口,这就是为什么WPF菜单
可能会超过包含它的窗口HWND的边缘。
当您使用HwndHost在WPF中放置HWND时,WPF会通知Win32如何
相对于WPF窗口HWND定位新的子HWND。A.
与HWND相关的概念是每个HWND内部和之间的透明度。
本主题“技术区域概述”中也讨论了这一点
抄袭
我建议您研究一种跟踪渲染区域的方法,并在其前面创建一个“可怕”的子窗口。
您可以做的其他研究是尝试查找/获取WPF图形缓冲区,并使用指针和一些高级内存编程将渲染场景直接注入其中。您必须实现一个承载Win32窗口的类。此类继承自 此外,您必须重写
HwndHost.BuildWindowCore
和HwndHost.destroy WindowCore
方法:
HandleRef BuildWindowCore(HandleRef hwndParent)
{
HWND parent = reinterpret_cast<HWND>(hwndParent.Handle.ToPointer());
// here create your Window and set in the CreateWindow function
// its parent by passing the parent variable defined above
m_hwnd = CreateWindow(...,
parent,
...);
return HandleRef(this, IntPtr(m_hwnd));
}
void DestroyWindowCore(HandleRef hwnd)
{
DestroyWindow(m_hwnd); // hwnd.Handle
}
HandleRef BuildWindowCore(HandleRef hwndParent)
{
HWND parent=reinterpret_cast(hwndParent.Handle.ToPointer());
//在这里创建您的窗口并在CreateWindow函数中设置
//通过传递上面定义的父变量
m_hwnd=CreateWindow(。。。,
父母亲
...);
返回HandleRef(这个,IntPtr(m_hwnd));
}
空心窗芯(HandleRef hwnd)
{
DestroyWindow(m_hwnd);//hwnd.Handle
}
请遵循本教程:。我将根据第19章发布的WPF 4.5尽我所能回答这个问题。如果您想查找,可以在“混合DirectX内容和WPF内容”小节中找到所有信息
你的C++ DLL应该有3种公开方法:初始化()、清除()和Read()。 有趣的方法是Initialize()和InitD3D(),Initialize()调用它们:
让我们继续讨论XAML代码:
xmlns:interop="clr-namespace:System.Windows.Interop;assembly=PresentationCore"
<Button.Background>
<ImageBrush>
<ImageBrush.ImageSource>
<interop:D3DImage x:Name="d3dImage" />
</ImageBrush.ImageSource>
</ImageBrush>
</Button.Background>
CompositionTarget.Rendering事件在呈现UI之前激发。您应该在其中呈现DirectX内容:
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
if (d3dImage.IsFrontBufferAvailable)
{
d3dImage.Lock();
DLL.Render();
// Invalidate the whole area:
d3dImage.AddDirtyRect(new Int32Rect(0, 0, d3dImage.PixelWidth, d3dImage.PixelHeight));
d3dImage.Unlock();
}
}
基本上就是这样,我希望有帮助。现在只需要一些重要的旁注:
- 始终锁定图像,以避免WPF部分绘制帧
- 不要在Direct 3D设备上调用Present。WPF根据传递给d3dImage.SetBackBuffer()的曲面显示自己的backbuffer李>
- 应处理事件IsFrontBufferAvailableChanged,因为有时frontbuffer可能变得不可用(例如,当用户进入锁定屏幕时)。您应该根据缓冲区可用性释放或获取资源
private void d3dImage_IsFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs e) { if (d3dImage.IsFrontBufferAvailable) { initialize(); } else { // Cleanup: CompositionTarget.Rendering -= CompositionTarget_Rendering; DLL.Cleanup(); } }
- 可能会有帮助
这是一个包含direct2d视图的级别编辑器我将搜索如何在WPF应用程序中托管direct2d的示例。好问题。你有访问DLL的权限吗?你能更改它的代码吗?我相信对CreateWindow()的调用是有问题的,因为WPF与WIC非常接近,所以我会将d2d1.CreateWicBitmapRenderTarget与您的IWicBitmap一起使用。然后,可以在从WPF的抽象位图源派生的类中使用此IWicBitmap(与InteropBitmap类似,但与您自己的类一起使用,因为WPF不公开其WIC位图…)。此位图源现在可以是面板的子级。如果你有一个示例应用程序可以工作,我们可以进一步开发。@多米尼克是的,我可以改变我的C++项目的代码。如何使用Windows窗体?可能在Windows窗体中,每个控件都有C/C++ Win32 HWND格式的句柄,可以通过调用Mulk.句柄属性来获得它,返回INTPTR,我相信你可以投给HWND。参考:我不能使用Direct3D,我需要使用Direct2D。afaik D3DImage也可以承载Direct2D内容。@Nick Direct2D是一个针对Direct3D子集的库。它如何回答这个问题?
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
if (d3dImage.IsFrontBufferAvailable)
{
d3dImage.Lock();
DLL.Render();
// Invalidate the whole area:
d3dImage.AddDirtyRect(new Int32Rect(0, 0, d3dImage.PixelWidth, d3dImage.PixelHeight));
d3dImage.Unlock();
}
}
private void d3dImage_IsFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (d3dImage.IsFrontBufferAvailable)
{
initialize();
}
else
{
// Cleanup:
CompositionTarget.Rendering -= CompositionTarget_Rendering;
DLL.Cleanup();
}
}