Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将Direct2D渲染重定向到WPF控件_C#_C++_Wpf_Directx_Direct2d - Fatal编程技术网

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();
           }
       }